Przejdź do głównej zawartości

Exception: typowana hierarchia wyjątków

Każdy wyjątek zgłaszany przez NextPDF rozszerza jedną abstrakcyjną klasę bazową, NextPdfException, dzięki czemu dowolny błąd silnika można obsłużyć jednym blokiem catch. Każdy wyjątek domenowy implementuje interfejs ContextAwareExceptionInterface i udostępnia ustrukturyzowane pola diagnostyczne na potrzeby rejestrowania zdarzeń oraz monitorowania wydajności aplikacji (APM), bez parsowania tekstu komunikatu.

Okno terminala
composer require nextpdf/core:^3

Hierarchia składa się z trzech warstw:

RuntimeException (PHP SPL)
└── NextPdfException (abstract; implements ContextAwareExceptionInterface)
├── InvalidConfigException
├── FontNotFoundException
├── FontParsingException
├── ImageProcessingException
├── SignatureException
├── EncryptionException
├── WriterException
├── PageLayoutException
├── HtmlParsingException
├── CompressionException
├── NotImplementedException
├── … (23 domain exceptions total)
└── Strict\StrictModeViolation (abstract)
├── Strict\IncompatibleRenderingModeException
├── Strict\OracleConformanceFailure
└── Strict\UnregisteredCssDeviation

NextPdfException rozszerza klasę RuntimeException ze standardowej biblioteki PHP (SPL). Przechwycenie RuntimeException obejmuje także błędy NextPDF. Przechwycenie NextPdfException zawęża obsługę do błędów silnika. Aby przeprowadzić ukierunkowane odzyskiwanie, przechwyć klasę liścia. Poddrzewo Strict\ grupuje naruszenia trybu zgodności pod abstrakcyjną klasą StrictModeViolation, która również rozszerza NextPdfException.

Kontekst, a nie kody tekstowe. NextPDF identyfikuje błąd na podstawie jego typu PHP, a nie tekstowego kodu błędu. Klasy wyjątków nie definiują żadnej stałej kodu NPDF-####. Zamiast tego ContextAwareExceptionInterface::getContext() zwraca tablicę array<string, mixed> z prymitywnymi polami w notacji snake_case, które można bezpiecznie zserializować do ładunku dziennika lub APM. Domyślnie NextPdfException::getContext() zwraca []. Każdy wyjątek domenowy przesłania tę metodę i zwraca pola właściwe dla danego niepowodzenia. Na przykład FontNotFoundException::getContext() zwraca font_name, search_paths oraz fallback_attempted. WriterException zwraca output_path oraz writer_state. InvalidConfigException zwraca config_key, given_value oraz expected_type. Stabilne identyfikatory tekstowe NEXTPDF_W_* należą do nieprzerywającego działania wyliczenia WarningCode w module Support, a nie do wyjątków.

Możliwość podjęcia działania. Blok dokumentacyjny klasy każdego wyjątku domenowego wskazuje, kto może na niego zareagować: programista, infrastruktura albo kod wywołujący bibliotekę. InvalidConfigException to błąd programisty; popraw konfigurację. FontNotFoundException to błąd programisty lub infrastruktury; zweryfikuj ścieżkę albo uprawnienia pliku. WriterException to błąd infrastruktury; sprawdź dysk, uprawnienia lub strumień wyjściowy. NotImplementedException to błąd kodu wywołującego; usuń wywołanie albo przypnij wersję, która dostarcza wskazane uzupełnienie. Kilka wyjątków udostępnia nazwane konstruktory dla precyzyjnych przyczyn źródłowych: SignatureException::ltvCapabilityMissing(), ::tsaRequired() i podobne. Operatorzy widzą rzeczywistą przyczynę zamiast ogólnego komunikatu.

SymbolRodzajKluczowe składowe
NextPDF\Contracts\ContextAwareExceptionInterfaceinterfejsgetContext(): array<string, mixed>
NextPDF\Exception\NextPdfExceptionklasa abstrakcyjnarozszerza RuntimeException; getContext() (domyślnie [])
NextPDF\Exception\InvalidConfigExceptionfinalnagetConfigKey(), getGivenValue(), getExpectedType(), getContext()
NextPDF\Exception\FontNotFoundExceptionfinalnagetFontName(), getSearchPaths(), wasFallbackAttempted(), getContext()
NextPDF\Exception\SignatureExceptionfinalnagetCertInfo(), getSignatureLevel(), getDetail(), getContext(); konstruktory nazwane ltvCapabilityMissing(), tsaRequired(), httpClientMissing(), …
NextPDF\Exception\WriterExceptionfinalnagetOutputPath(), getWriterState(), getContext()
NextPDF\Exception\PageLayoutExceptionfinalnagetPageNumber(), getContext()
NextPDF\Exception\NotImplementedExceptionfinalna$feature, $followUp
NextPDF\Exception\Strict\StrictModeViolationabstrakcyjnarozszerza NextPdfException
NextPDF\Exception\Strict\IncompatibleRenderingModeExceptionfinalnarozszerza StrictModeViolation

Pełny zbiór klas liści (23): BarcodeEncoderNotFoundException, BarcodeException, CompressionException, ContentStreamBalanceException, CssParserLimitExceededException, CssResolutionBudgetExceededException, EncryptionException, FontNotFoundException, FontParsingException, GraphicsStateBalanceException, HtmlParsingException, ImageProcessingException, InvalidConfigException, LinearizationInvariantException, LinearizationUnimplementedException, MissingShadingResourceException, NotImplementedException, PageLayoutException, PdfRViolationException, SignatureException, TemplateException, UnsupportedAlgorithmException, WriterException.

Przechwyć dowolny błąd silnika przez obsłużenie typu bazowego.

<?php
declare(strict_types=1);
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('out.pdf');
} catch (NextPdfException $e) {
\error_log($e->getMessage());
}

Gotowy do uruchomienia przykład examples/15-exception-handling.php pokazuje ten wzorzec.

Przeprowadź odzyskiwanie na poziomie klasy liścia i przekaż ustrukturyzowany kontekst do potoku rejestrowania.

<?php
declare(strict_types=1);
use NextPDF\Contracts\ContextAwareExceptionInterface;
use NextPDF\Core\Document;
use NextPDF\Exception\FontNotFoundException;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
function render(Document $doc, LoggerInterface $logger): void
{
try {
$doc->setFont('Brand-Sans', '', 12);
$doc->cell(0, 10, 'Invoice');
$doc->save('invoice.pdf');
} catch (FontNotFoundException $e) {
// Targeted recovery: fall back to a built-in font.
$logger->warning($e->getMessage(), $e->getContext());
$doc->setFont('helvetica', '', 12);
$doc->save('invoice.pdf');
} catch (NextPdfException $e) {
// Any other engine error: structured context, then rethrow.
$context = $e instanceof ContextAwareExceptionInterface
? $e->getContext()
: [];
$logger->error($e->getMessage(), $context);
throw $e;
}
}
  • Kolejność bloków catch ma znaczenie. Klasy liści wymieniaj przed NextPdfException; wcześniejszy catch (NextPdfException) pochłania każdą podklasę.
  • Klucze getContext() używają notacji snake_case, a wartości są typami prymitywnymi lub listami typów prymitywnych, bez zagnieżdżonych obiektów. Ładunek można bezpiecznie zserializować do formatu JavaScript Object Notation (JSON).
  • Bazowy NextPdfException::getContext() zwraca []. Podklasa, która go nie przesłania, nie zawiera żadnych pól ustrukturyzowanych. W takim przypadku polegaj na getMessage().
  • NextPdfException jest abstrakcyjny; nie można go utworzyć bezpośrednio. Zgłaszaj konkretną klasę liścia.
  • NotImplementedException jest celowo jednoznaczny. Sygnalizuje świadomie nieobecną implementację, a nie przejściowe niepowodzenie. Nie ponawiaj go.
  • Naruszenia Strict\* wskazują na złamanie kontraktu trybu zgodności, a nie na możliwy do naprawienia błąd czasu wykonania. Traktuj je jak wady konfiguracji lub danych wejściowych.
  • Nie istnieje żadna stała tekstowego kodu błędu. Dopasowuj według typu wyjątku. Przekazuj getContext() odbiorcom maszynowym.

Konstrukcja wyjątku wykonuje jedną alokację obiektu oraz wywołanie sprintf budujące komunikat: O(1). getContext() zwraca małą tablicę asocjacyjną zbudowaną z już przechowywanych pól: O(1) względem liczby pól. Wyjątki występują na ścieżce niepowodzenia, a nie na ścieżce krytycznej. Koszt jest pomijalny w porównaniu z pracą, która zakończyła się niepowodzeniem. Domyślny performance_budget dla tej strony referencyjnej to wall_ms: 1500, peak_mb: 64.

Pola kontekstu mogą zawierać szczegóły pochodzące z dokumentu. FontNotFoundException zawiera ścieżki wyszukiwania w systemie plików, WriterException zawiera ścieżkę wyjściową, a InvalidConfigException zawiera podaną wartość. Przed przekazaniem kontekstu do mniej zaufanego odbiornika dzienników wyczyść pola albo przekaż wyłącznie listę dozwolonych kluczy, ponieważ ścieżki i wartości mogą ujawniać układ wdrożenia lub dane wprowadzone przez użytkownika. Komunikaty wyjątków są czytelne dla człowieka i mogą zawierać te same szczegóły. Nie pokazuj surowych komunikatów użytkownikom końcowym w kontekście wrażliwym pod względem bezpieczeństwa. SignatureException celowo łączy komunikat z konkretną przyczyną źródłową, taką jak brakujący pakiet lub pusty Uniform Resource Locator (URL) urzędu znaczników czasu (Time Stamping Authority, TSA), aby operatorzy mogli przeprowadzić triage bez przeszukiwania miejsc wywołań. Te szczegóły są przeznaczone dla operatora, a nie dla użytkownika końcowego.

Ten moduł definiuje model błędów silnika i nie zawiera żadnego odwołania do normatywnego standardu. Wyjątki zgłaszane przy naruszeniach standardów, na przykład PdfRViolationException lub Strict\OracleConformanceFailure, odwołują się do właściwej klauzuli w module wykrywającym naruszenie, a nie tutaj.

  • /modules/core/contracts/ — definicja ContextAwareExceptionInterface
  • /modules/core/observability/ — przekazywanie getContext() do APM
  • /modules/core/config/InvalidConfigException, NotImplementedException
  • /modules/core/support/DegradedException; WarningCode (NEXTPDF_W_*)
  • /modules/core/event/InvalidConfigException z addListener()

Słownik: wyjątek świadomy kontekstu · polityka degradacji