Obsługa błędów z uwzględnieniem hierarchii wyjątków NextPDF
W skrócie
Dział zatytułowany „W skrócie”NextPDF zgłasza typowane wyjątki w stanach wyjątkowych. Nigdy nie ukrywa błędu w zwracanej wartości false ani null. Każdy wyjątek domenowy rozszerza tę samą abstrakcyjną klasę bazową NextPdfException i udostępnia ustrukturyzowany kontekst diagnostyczny przez ContextAwareExceptionInterface. Ten przepis pokazuje, gdzie przechwytywać wyjątki i jak rejestrować ustrukturyzowany kontekst na potrzeby potoku APM. Pokazuje też, których awarii pojedyncza uniwersalna klauzula przechwytująca nie obejmuje.
Instalacja
Dział zatytułowany „Instalacja”composer require nextpdf/core:^3Nie jest wymagane żadne dodatkowe rozszerzenie.
Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Hierarchia wygląda następująco:
RuntimeException └── NextPdfException (abstract, implements ContextAwareExceptionInterface) ├── InvalidConfigException ├── FontNotFoundException ├── FontParsingException ├── ImageProcessingException ├── WriterException ├── SignatureException ├── EncryptionException ├── HtmlParsingException ├── … (every domain exception under NextPDF\Exception) └── Strict\StrictModeViolation (abstract) ├── Strict\IncompatibleRenderingModeException └── Strict\OracleConformanceFailureTa hierarchia ma dwie praktyczne konsekwencje, obie zweryfikowane na podstawie kodu źródłowego:
catch (NextPdfException $e)przechwytuje każdy wyjątek w przestrzeniNextPDF\Exception, łącznie z naruszeniami trybu ścisłego. Wszystkie rozszerzają abstrakcyjną klasę bazową.- Nie przechwytuje wszystkich wyjątków, które biblioteka może zgłosić.
NextPDF\Support\DegradedExceptionrozszerza klasęRuntimeExceptionbezpośrednio, a nieNextPdfException. Dlategocatch (NextPdfException $e)nie przechwytuje odrzucenia wynikającego z zasady degradacji. Aby je obsłużyć, przechwyć jawnieDegradedException(lub szerszyRuntimeException). Ten przepis wyraźnie wskazuje tę granicę, zamiast traktować jedną uniwersalną klauzulę przechwytującą jako pełne pokrycie.
NextPdfException::getContext() zwraca array<string, mixed> z kluczami w notacji snake_case oraz wartościami będącymi wyłącznie prymitywami lub listami prymitywów. Możesz ją bezpośrednio serializować jako tablicę kontekstu rejestratora zgodnego z PSR-3. Zgodnie z PSR-3 §1.3 wyjątek umieszcza się pod kluczem kontekstu 'exception'. Metoda getContext() w NextPDF dodaje obok tego klucza szczegóły domenowe, a nie sam obiekt wyjątku.
Powierzchnia API
Dział zatytułowany „Powierzchnia API”Ta powierzchnia API wynika z PHPDoc klas NextPDF\Exception\NextPdfException, NextPDF\Contracts\ContextAwareExceptionInterface, konkretnych wyjątków domenowych (na przykład NextPDF\Exception\FontNotFoundException, z metodami getFontName() / getSearchPaths() / wasFallbackAttempted()) oraz NextPDF\Support\DegradedException (która przechowuje Capability oraz DegradationPolicy). Poniższe przykłady używają NextPdfException::getContext() oraz akcesorów poszczególnych wyjątków.
Przykład kodu — szybki start
Dział zatytułowany „Przykład kodu — szybki start”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\NextPdfException;
try { $doc = Document::createStandalone(); $doc->addPage(); $doc->setFont('helvetica', '', 12); $doc->cell(0, 10, 'Hello'); $doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');} catch (NextPdfException $e) { // Every NextPDF\Exception\* (and strict-mode violation) lands here. // $e->getContext() is APM-safe structured detail. error_log($e->getMessage());}Przykład kodu — produkcja
Dział zatytułowany „Przykład kodu — produkcja”Kompletny przykład pokazuje szczegółowe klauzule przechwytujące, rejestrowanie ustrukturyzowanego kontekstu oraz granicę DegradedException. Zachowuje także kanał wyjściowy dla środowiska testowego.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Contracts\ContextAwareExceptionInterface;use NextPDF\Exception\FontNotFoundException;use NextPDF\Exception\NextPdfException;use NextPDF\Support\DegradedException;
/** * A minimal PSR-3-shaped sink. In production this is your real logger; * the exception goes under the 'exception' key (PSR-3 §1.3) and the * NextPDF structured context is merged in as domain detail. * * @param array<string, mixed> $context */function logError(string $message, array $context): void{ fwrite(STDERR, $message . ' ' . json_encode($context, JSON_THROW_ON_ERROR) . "\n");}
$doc = Document::createStandalone();$doc->setTitle('Exception handling patterns');
try { $doc->addPage(); $doc->setFont('helvetica', 'B', 16); $doc->cell(0, 12, 'Exception-aware error handling', newLine: true);
// This call succeeds; the catch blocks below show the SHAPE of handling. $doc->setFont('helvetica', '', 11); $doc->cell(0, 8, 'Catch specifically, then fall back to the base.', newLine: true);} catch (FontNotFoundException $e) { // Most specific first: actionable, typed accessors. logError('Font missing — using a fallback face', [ 'exception' => $e::class, 'font_name' => $e->getFontName(), 'searched' => $e->getSearchPaths(), 'fallback' => $e->wasFallbackAttempted(), ]);} catch (NextPdfException $e) { // Catch-all for every NextPDF\Exception\* including strict violations. $context = ['exception' => $e::class]; if ($e instanceof ContextAwareExceptionInterface) { $context += $e->getContext(); } logError($e->getMessage(), $context);} catch (DegradedException $e) { // BOUNDARY: DegradedException extends RuntimeException directly, NOT // NextPdfException. The catch above would NOT have caught it. This // explicit block (or a broader RuntimeException) is required. logError('Capability degraded under the active policy', [ 'exception' => $e::class, 'capability' => $e->capability->id, 'policy' => $e->policy->value, ]);}
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');
fwrite(STDERR, "Document built; handlers wired.\n");STDOUT pozostaje nieużywany przez środowisko testowe; plik PDF trafia wyłącznie do NEXTPDF_COOKBOOK_OUTPUT.
Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”- Porządkuj bloki catch od szczegółowych do ogólnych. PHP dopasowuje pierwszą zgodną klauzulę
catch. Klauzulacatch (NextPdfException $e)umieszczona przedcatch (FontNotFoundException $e)sprawia, że blok szczegółowy staje się martwym kodem. DegradedExceptionnie jestNextPdfException. Zgodnie z weryfikacją kodu źródłowegoDegradedExceptionrozszerzaRuntimeException. Pojedyncza klauzulacatch (NextPdfException $e)pozwala, aby odrzucenie wynikające ze ścisłej degradacji rozpropagowało się dalej. Przechwyć je jawnie (lub przechwyćRuntimeException), gdy obowiązuje zasada degradacji.- Metoda
getContext()jest z założenia bezpieczna dla APM. Klucze są w notacji snake_case. Wartości są prymitywami lub listami prymitywów, bez zagnieżdżonych obiektów i bez zasobów. Możesz ją serializować bezpośrednio. Nigdy nie zawiera bajtów dokumentu. - Nie parsuj komunikatów wyjątków. Komunikaty są czytelne dla człowieka i mogą się zmieniać. Jako stabilnej powierzchni maszynowej używaj typowanych akcesorów (
getFontName(),capability->idi tak dalej) orazgetContext(). - Nie polegaj na nieaktualnej liczbie. Starsze materiały mogą podawać stałą liczbę „N wyjątków domenowych”. Hierarchia rozrasta się wraz z kolejnymi wydaniami. Polegaj na typie bazowym
NextPdfExceptioni operatorzeinstanceof, nigdy na zakodowanej na stałe liczbie. - Komunikaty z symbolami zastępczymi PSR-3 pozostają ciągami znaków. Podczas rejestrowania pozostaw komunikat jako ciąg znaków z tokenami
{placeholder}, a wartości umieść w tablicy kontekstu (PSR-3 §1.2). Nie interpoluj obiektu wyjątku do komunikatu.
Wydajność
Dział zatytułowany „Wydajność”Obsługa wyjątków nie dodaje żadnego narzutu w stanie ustalonym. NextPDF zgłasza wyjątki wyłącznie w stanach wyjątkowych, a getContext() buduje niewielką tablicę na żądanie. Limit performance_budget (wall_ms: 2000, peak_mb: 96) dotyczy przebiegu środowiska testowego dla tego przepisu, a nie dowolnych dokumentów.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”- Metoda
getContext()została zaprojektowana tak, aby była bezpieczna do rejestrowania: wyłącznie prymitywy, bez zawartości dokumentu i bez bajtów pliku. Nadal odpowiadasz za wartości, które dodajesz do kontekstu dziennika. Oczyść wszystko, co pochodzi od użytkownika (na przykład ścieżkę pliku), zgodnie ze swoją zasadą rejestrowania, zanim trafi do odbiorcy. - Nie wyświetlaj użytkownikom końcowym surowych komunikatów wyjątków w sposób ujawniający układ systemu plików. Pokaż ogólny komunikat, a ustrukturyzowany kontekst rejestruj po stronie serwera.
Zgodność
Dział zatytułowany „Zgodność”| Stwierdzenie | Specyfikacja | Klauzula | reference_id |
|---|---|---|---|
Wyjątek należy umieścić w kontekście dziennika PSR-3 pod kluczem exception. | PSR-3 | §1.3 | |
| Komunikaty dziennika pozostają ciągami znaków; nazwy symboli zastępczych są odwzorowywane na klucze kontekstu. | PSR-3 | §1.2 | |
| Data modyfikacji jest generowana ponownie przy każdym zapisie, więc wynik jest stabilny strukturalnie (a nie bajtowo). | ISO 32000-2 | §14.3 |
Ten przepis jest weryfikowany przy użyciu strukturalnego profilu odtwarzalności. Wynik zawiera w trailerze /ID oraz datę modyfikacji, które są generowane ponownie przy każdym zapisie, więc nie da się osiągnąć identyczności bajtowej. Struktura znormalizowana przez qpdf pozostaje stabilna.