Menangani kesalahan dengan hierarki exception NextPDF
Sekilas pandang
Bagian berjudul “Sekilas pandang”NextPDF melempar exception bertipe untuk kondisi yang tidak biasa. NextPDF tidak pernah menyembunyikan kesalahan di balik nilai kembalian false atau null. Setiap exception domain memperluas kelas dasar abstrak yang sama, NextPdfException, dan mengekspos konteks diagnostik terstruktur melalui ContextAwareExceptionInterface. Resep ini menunjukkan di mana Anda perlu menangkap exception dan bagaimana mencatat konteks terstruktur untuk alur application performance monitoring (APM). Resep ini juga menunjukkan kegagalan mana yang tidak dicakup oleh satu penangkap menyeluruh.
Pemasangan
Bagian berjudul “Pemasangan”composer require nextpdf/core:^3Anda tidak memerlukan ekstensi tambahan apa pun.
Gambaran konseptual
Bagian berjudul “Gambaran konseptual”Hierarkinya adalah:
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\OracleConformanceFailureHierarki ini memiliki dua konsekuensi praktis, dan keduanya telah diverifikasi terhadap kode sumber:
catch (NextPdfException $e)menangkap setiap exception di bawahNextPDF\Exception, termasuk pelanggaran mode ketat. Semuanya memperluas basis abstrak tersebut.- Ini tidak menangkap semua hal yang dapat dilempar oleh pustaka ini.
NextPDF\Support\DegradedExceptionmemperluasRuntimeExceptionsecara langsung, bukanNextPdfException. Jadi, sebuahcatch (NextPdfException $e)tidak menangkap penolakan kebijakan degradasi. Untuk menanganinya, tangkapDegradedException(atauRuntimeExceptionyang lebih luas) secara eksplisit. Resep ini membuat batasan tersebut jelas, alih-alih memperlakukan satu penangkap menyeluruh sebagai cakupan lengkap.
NextPdfException::getContext() mengembalikan array<string, mixed> dengan kunci snake_case dan hanya memuat nilai primitif atau daftar nilai primitif. Anda dapat menserialisasikannya langsung ke array konteks logger PSR-3. PSR-3 §1.3 menempatkan exception di bawah kunci konteks 'exception'. getContext() milik NextPDF menambahkan detail domain di samping kunci tersebut, bukan objek exception itu sendiri.
Permukaan API
Bagian berjudul “Permukaan API”Permukaan API ini bersumber dari PHPDoc pada NextPDF\Exception\NextPdfException, NextPDF\Contracts\ContextAwareExceptionInterface, exception domain konkret (misalnya NextPDF\Exception\FontNotFoundException, dengan getFontName() / getSearchPaths() / wasFallbackAttempted()), dan NextPDF\Support\DegradedException (yang membawa Capability dan DegradationPolicy). Contoh-contoh di bawah ini menggunakan NextPdfException::getContext() dan accessor per-exception.
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”<?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());}Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Contoh lengkap ini menunjukkan penangkapan granular, pencatatan konteks terstruktur, dan batasan DegradedException. Contoh ini juga mempertahankan saluran output 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 tetap tersedia untuk harness; PDF hanya dikirim ke NEXTPDF_COOKBOOK_OUTPUT.
Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”- Urutkan blok catch dari yang spesifik → umum. PHP mencocokkan blok
catchkompatibel pertama. Sebuahcatch (NextPdfException $e)yang ditempatkan sebelumcatch (FontNotFoundException $e)membuat blok spesifik tersebut menjadi kode mati. DegradedExceptionbukanlah sebuahNextPdfException. Telah diverifikasi terhadap kode sumber bahwa ia memperluasRuntimeException. Sebuahcatch (NextPdfException $e)tunggal membiarkan penolakan degradasi-ketat merambat ke atas. Tangkap exception itu (atauRuntimeException) secara eksplisit ketika kebijakan degradasi sedang berlaku.getContext()aman untuk APM secara kontraktual. Kunci-kuncinya menggunakan snake_case. Nilainya berupa primitif atau daftar primitif, tanpa objek bersarang dan tanpa resource. Anda dapat menserialisasikannya secara langsung. Metode ini tidak pernah berisi byte dokumen.- Jangan mengurai pesan exception. Pesan ditujukan untuk dibaca manusia dan dapat berubah. Gunakan accessor bertipe (
getFontName(),capability->id, dan seterusnya) dangetContext()sebagai permukaan mesin yang stabil. - Peringatan jumlah usang. Materi yang lebih lama mungkin menyebutkan jumlah tetap “N exception domain”. Hierarki ini dapat bertambah seiring rilis-rilis berikutnya. Andalkan tipe dasar
NextPdfExceptiondaninstanceof, jangan pernah pada jumlah yang ditulis secara hard-coded. - Placeholder PSR-3 tetap berupa string. Saat Anda mencatat log, jaga agar pesan tetap berupa string dengan token
{placeholder}, dan tempatkan nilai di dalam array konteks (PSR-3 §1.2). Jangan menginterpolasikan objek exception ke dalam pesan.
Performa
Bagian berjudul “Performa”Penanganan exception tidak menambah biaya pada keadaan tunak. NextPDF hanya melempar exception untuk kondisi yang tidak biasa, dan getContext() membangun array kecil sesuai permintaan. performance_budget (wall_ms: 2000, peak_mb: 96) membatasi proses harness untuk resep ini, bukan dokumen sembarang.
Catatan keamanan
Bagian berjudul “Catatan keamanan”getContext()dirancang agar aman untuk pencatatan log: hanya primitif, tanpa muatan dokumen, dan tanpa byte berkas. Anda tetap bertanggung jawab atas nilai-nilai yang Anda tambahkan ke dalam konteks log. Bersihkan apa pun yang dipasok pengguna (path berkas, sebagai contoh) sesuai kebijakan pencatatan log Anda sebelum mencapai sink.- Jangan menampilkan pesan exception mentah kepada pengguna akhir dengan cara yang membocorkan tata letak sistem berkas. Tampilkan pesan generik, dan catat konteks terstruktur di sisi server.
Kesesuaian
Bagian berjudul “Kesesuaian”| Pernyataan | Spesifikasi | Klausa | reference_id |
|---|---|---|---|
Sebuah exception ditempatkan dalam konteks log PSR-3 di bawah kunci exception. | PSR-3 | §1.3 | |
| Pesan log tetap berupa string; nama placeholder dipetakan ke kunci konteks. | PSR-3 | §1.2 | |
| Tanggal modifikasi dibuat ulang setiap penyimpanan, sehingga keluaran stabil secara struktural (bukan byte). | ISO 32000-2 | §14.3 |
Resep ini diverifikasi dengan profil keterulangan struktural. Keluaran memuat trailer /ID dan tanggal modifikasi yang dibuat ulang pada setiap penyimpanan, sehingga identitas byte tidak dapat dicapai. Struktur yang dinormalisasi oleh qpdf tetap stabil.