Trate erros com a hierarquia de exceções do NextPDF
Visão geral
Seção intitulada “Visão geral”O NextPDF lança exceções tipadas para estados excepcionais. Ele nunca mascara um erro retornando false ou null. Toda exceção de domínio estende a mesma base abstrata, NextPdfException, e expõe um contexto de diagnóstico estruturado por meio de ContextAwareExceptionInterface. Esta receita mostra onde capturar exceções e como registrar contexto estruturado em um pipeline de monitoramento de desempenho de aplicações (APM). Ela também mostra quais falhas um catch-all único não cobre.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Você não precisa instalar nenhuma extensão adicional.
Visão conceitual
Seção intitulada “Visão conceitual”A hierarquia é:
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\OracleConformanceFailureEssa hierarquia traz duas consequências práticas, ambas verificadas no código-fonte:
catch (NextPdfException $e)captura toda exceção emNextPDF\Exception, incluindo as violações de modo estrito. Todas elas estendem a base abstrata.- Ele não captura tudo o que a biblioteca pode lançar.
NextPDF\Support\DegradedExceptionestendeRuntimeExceptiondiretamente, nãoNextPdfException. Portanto, umcatch (NextPdfException $e)não captura uma rejeição de política de degradação. Para tratar esse caso, captureDegradedException(ou o mais amploRuntimeException) explicitamente. Esta receita explicita esse limite em vez de tratar um único catch-all como cobertura completa.
NextPdfException::getContext() retorna um array<string, mixed> com chaves em snake_case e somente valores primitivos ou listas de valores primitivos. Você pode serializá-lo diretamente no array de contexto de um logger PSR-3. A PSR-3 §1.3 coloca uma exceção sob a chave de contexto 'exception'. O getContext() do NextPDF adiciona detalhes de domínio junto dessa chave, não o objeto da exceção em si.
Superfície da API
Seção intitulada “Superfície da API”Esta superfície da API vem do PHPDoc de NextPDF\Exception\NextPdfException, de NextPDF\Contracts\ContextAwareExceptionInterface, das exceções de domínio concretas (por exemplo NextPDF\Exception\FontNotFoundException, com getFontName() / getSearchPaths() / wasFallbackAttempted()), e de NextPDF\Support\DegradedException (que carrega o Capability e a DegradationPolicy). Os exemplos abaixo usam NextPdfException::getContext() e os acessores específicos de cada exceção.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?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());}Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”O exemplo completo mostra capturas granulares, registro de contexto estruturado e o limite do DegradedException. Ele também mantém o canal de saída do harness.
<?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 fica livre para o harness; o PDF é gravado apenas em NEXTPDF_COOKBOOK_OUTPUT.
Casos extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- Ordene os blocos catch do específico → geral. O PHP usa o primeiro
catchcompatível. Umcatch (NextPdfException $e)colocado antes decatch (FontNotFoundException $e)torna o bloco específico código morto. DegradedExceptionnão é umaNextPdfException. A verificação no código-fonte confirma que ela estendeRuntimeException. Um únicocatch (NextPdfException $e)deixa uma rejeição de degradação estrita se propagar. Capture-a (ouRuntimeException) explicitamente quando a política de degradação estiver em jogo.getContext()é seguro para APM por contrato. As chaves ficam em snake_case. Os valores são primitivos ou listas de primitivos, sem objetos aninhados nem recursos. Você pode serializá-lo diretamente. Ele nunca contém bytes do documento.- Não faça parsing das mensagens de exceção. As mensagens são legíveis por humanos e podem mudar. Use os acessores tipados (
getFontName(),capability->id, e assim por diante) egetContext()como a superfície estável para máquina. - Ressalva sobre contagens desatualizadas. Material mais antigo pode citar um número fixo de “N exceções de domínio”. A hierarquia cresce a cada versão. Confie no tipo base
NextPdfExceptione eminstanceof, nunca em uma contagem fixa no código. - Os placeholders da PSR-3 permanecem strings. Ao registrar, mantenha a mensagem como uma string com tokens
{placeholder}e coloque os valores no array de contexto (PSR-3 §1.2). Não interpole o objeto da exceção na mensagem.
Desempenho
Seção intitulada “Desempenho”O tratamento de exceções não adiciona custo no caminho normal de execução. O NextPDF lança exceções apenas para estados excepcionais, e getContext() constrói um array pequeno sob demanda. O performance_budget (wall_ms: 2000, peak_mb: 96) limita a execução do harness para esta receita, não para documentos arbitrários.
Notas de segurança
Seção intitulada “Notas de segurança”getContext()foi projetado para ser seguro para logs: apenas primitivos, sem payload do documento e sem bytes de arquivo. Você ainda é responsável pelos valores que adiciona a um contexto de log. Limpe qualquer dado fornecido pelo usuário (um caminho de arquivo, por exemplo) de acordo com a política de logging antes que chegue a um sink.- Não exiba mensagens de exceção brutas para usuários finais de modo que vazem a estrutura do sistema de arquivos. Mostre uma mensagem genérica e registre o contexto estruturado no servidor.
Conformidade
Seção intitulada “Conformidade”| Declaração | Especificação | Cláusula | reference_id |
|---|---|---|---|
Uma exceção pertence ao contexto de log da PSR-3 sob a chave exception. | PSR-3 | §1.3 | |
| As mensagens de log permanecem strings; os nomes de placeholders mapeiam para chaves de contexto. | PSR-3 | §1.2 | |
| A data de modificação é regenerada a cada salvamento, então a saída é estável estruturalmente (não byte a byte). | ISO 32000-2 | §14.3 |
Esta receita é verificada com o perfil de reprodutibilidade estrutural. A saída inclui um /ID no trailer e uma data de modificação que são regenerados a cada salvamento, portanto a identidade byte a byte não é alcançável. A estrutura normalizada pelo qpdf permanece estável.