Gestiona errores con la jerarquía de excepciones de NextPDF
De un vistazo
Sección titulada «De un vistazo»NextPDF lanza excepciones tipadas cuando se producen estados excepcionales. Nunca oculta un error devolviendo false o null. Todas las excepciones de dominio extienden una única base abstracta, NextPdfException, y exponen contexto de diagnóstico estructurado a través de ContextAwareExceptionInterface. Esta guía muestra cómo capturar con la granularidad adecuada y cómo registrar el contexto estructurado para una canalización de supervisión del rendimiento de aplicaciones (APM). También señala qué fallos no cubre el único bloque genérico.
Instalación
Sección titulada «Instalación»composer require nextpdf/core:^3No se requiere ninguna extensión adicional.
Resumen conceptual
Sección titulada «Resumen conceptual»La jerarquía es:
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\OracleConformanceFailureEsta jerarquía tiene dos consecuencias prácticas, ambas verificadas con el código fuente:
catch (NextPdfException $e)captura toda excepción bajoNextPDF\Exception, incluidas las violaciones del modo estricto. Todas extienden la base abstracta.- No captura todo lo que la biblioteca puede lanzar.
NextPDF\Support\DegradedExceptionextiendeRuntimeExceptiondirectamente, noNextPdfException. Por eso uncatch (NextPdfException $e)no captura un rechazo de la política de degradación. Para manejar ese caso, capturaDegradedException(o el más amplioRuntimeException) de forma explícita. Esta guía deja claro ese límite sin dar a entender que un único bloque genérico lo cubre todo.
NextPdfException::getContext() devuelve un array<string, mixed> con claves en snake_case y solo valores primitivos (o listas de primitivos), por lo que se puede serializar directamente en el array de contexto de un logger PSR-3. PSR-3 §1.3 coloca una excepción bajo la clave de contexto 'exception'. El getContext() de NextPDF añade detalles de dominio junto a ella, no el objeto de la excepción en sí.
Superficie de la API
Sección titulada «Superficie de la API»Esta superficie de la API se genera a partir del PHPDoc de NextPDF\Exception\NextPdfException, NextPDF\Contracts\ContextAwareExceptionInterface, las excepciones de dominio concretas (por ejemplo NextPDF\Exception\FontNotFoundException, con getFontName() / getSearchPaths() / wasFallbackAttempted()), y NextPDF\Support\DegradedException (que lleva el Capability y la DegradationPolicy). Los miembros que se usan a continuación son NextPdfException::getContext() y los accesores de cada excepción.
Muestra de código — Inicio rápido
Sección titulada «Muestra de código — Inicio 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());}Muestra de código — Producción
Sección titulada «Muestra de código — Producción»El ejemplo completo muestra la captura granular, el registro de contexto estructurado y el límite de DegradedException. También respeta el canal de salida del 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 queda libre para el harness; el PDF va únicamente a NEXTPDF_COOKBOOK_OUTPUT.
Casos límite y trampas
Sección titulada «Casos límite y trampas»- Ordenar los bloques catch de específico → general. PHP hace coincidir el primer
catchcompatible. Uncatch (NextPdfException $e)colocado antes decatch (FontNotFoundException $e)convierte el bloque específico en código muerto. DegradedExceptionno es unaNextPdfException. Verificada con el código fuente, extiendeRuntimeException. Un únicocatch (NextPdfException $e)deja que un rechazo de degradación estricta se propague sin capturarse. Capturarlo (oRuntimeException) de forma explícita cuando la política de degradación está en juego.getContext()es seguro para APM por contrato. Las claves están en snake_case. Los valores son primitivos o listas de primitivos, sin objetos anidados ni recursos. Se puede serializar directamente, y nunca contiene bytes del documento.- No analizar los mensajes de las excepciones. Los mensajes son legibles por personas y pueden cambiar. Los accesores tipados (
getFontName(),capability->id, etc.) ygetContext()son la superficie de máquina estable. - Advertencia sobre conteos obsoletos. Material más antiguo puede citar un número fijo de «N excepciones de dominio». La jerarquía crece a lo largo de las versiones. Conviene apoyarse en el tipo base
NextPdfExceptiony eninstanceof, nunca en un conteo codificado de forma fija. - Los marcadores de posición de PSR-3 siguen siendo cadenas. Al registrar, mantener el mensaje como una cadena con tokens
{placeholder}y poner los valores en el array de contexto (PSR-3 §1.2). No interpolar el objeto de la excepción dentro del mensaje.
Rendimiento
Sección titulada «Rendimiento»El manejo de excepciones no añade ningún costo durante el funcionamiento estable. NextPDF lanza solo en estados excepcionales, y getContext() construye un array pequeño bajo demanda. El performance_budget (wall_ms: 2000, peak_mb: 96) acota la ejecución de esta guía en el harness, no documentos arbitrarios.
Notas de seguridad
Sección titulada «Notas de seguridad»getContext()está diseñado para ser seguro en registros: solo primitivos, sin carga útil del documento, sin bytes de archivo. La aplicación sigue siendo responsable de los valores que añades a un contexto de registro. Sanear cualquier dato proporcionado por el usuario (una ruta de archivo, por ejemplo) según la política de registro antes de que llegue a un sink.- No mostrar mensajes de excepción sin procesar a los usuarios finales de una forma que revele la disposición del sistema de archivos. Exponer un mensaje genérico y registrar el contexto estructurado del lado del servidor.
Conformidad
Sección titulada «Conformidad»| Declaración | Especificación | Cláusula | reference_id |
|---|---|---|---|
Una excepción pertenece al contexto de registro de PSR-3 bajo la clave exception. | PSR-3 | §1.3 | |
| Los mensajes de registro siguen siendo cadenas; los nombres de los marcadores de posición se asignan a claves de contexto. | PSR-3 | §1.2 | |
| La fecha de modificación se regenera en cada guardado, así que la salida es estructuralmente estable (no byte a byte). | ISO 32000-2 | §14.3 |
Esta guía está verificada con el perfil de reproducibilidad estructural. La salida incluye un /ID del tráiler y una fecha de modificación que se regeneran en cada guardado, así que la identidad byte a byte no se puede alcanzar. La estructura normalizada por qpdf es estable.