Bir özellik olarak hatalar
Spec: ISO 9241-110, §5.6.4 ISO 9241-110 §5.6.4 Evidence: Code-backed
Bir bakışta
“Bir bakışta” başlıklı bölümNextPDF, istisna hiyerarşisini bir API yüzeyi olarak ele alır ve onu, istisnayı fırlatan yöntemlerle aynı özenle tasarlar. Her başarısızlık belirlidir, türlenmiştir, ihtiyaç duyduğunuz ayrıntı düzeyinde yakalanabilir ve günlükleriniz için yapılandırılmış bağlam taşır.
Bu sayfa, söz konusu yüzeyi motorun kendi kaynak kodunda gösterir: temel tür, türlenmiş alt sınıflar, kök nedeni mesaja bağlayan adlandırılmış kurucular ve her NextPDF istisnasının açığa çıkardığı yapılandırılmış bağlam.
Bu neden önemli
“Bu neden önemli” başlıklı bölümBir hata mesajı, motorun sizinle olası en kötü anda konuşmasıdır: üretim ortamında, gece 2 a.m.‘de ve teslim edilmesi gereken bir belge varken. O mesajın o anda söylediği şey, bir sonraki adımın bir düzeltme mi yoksa uzun bir araştırma mı olacağını belirler.
Genel bir RuntimeException: something went wrong size hiçbir çıkış yolu bırakmaz. Motorun başarısız olduğunu söyler, ancak neyin nerede başarısız olduğunu veya tam olarak ne yapılması gerektiğini söylemez. İnsan faktörleri rehberliği bu konuda açıktır. Bir hata, onu düzeltmek araştırma projesi değil, bariz bir sonraki adım olacak kadar iyi açıklanmalıdır ( Spec: ISO 9241-110, §5.6.4.3 ISO 9241-110 §5.6.4.3 ). Nedeni ve çözümü adlandıran bir istisna, hoş bir ayrıntıdan ibaret değildir. Beş dakikalık bir düzeltme ile beş saatlik bir araştırma arasındaki farktır.
Kısa sürüm
“Kısa sürüm” başlıklı bölüm- Her NextPDF başarısızlığı tek bir soyut temelden,
NextPdfExceptionsınıfından türer; böylece tüm kitaplık hatalarını tek bir türle yakalayabilirsiniz. - Bu temelin altında belirli, türlenmiş alt sınıflar yer alır — bulunamayan bir yazı tipi, geçersiz bir yapılandırma, başarısız olan bir imza işlemi — böylece tam olarak ele alabileceğiniz başarısızlığı yakalayabilirsiniz.
- Her NextPDF istisnası
ContextAwareExceptionInterfacearabirimini uygular vegetContext()yöntemini açığa çıkarır: yapılandırılmış, günlüğe güvenle yazılabilecek bir eşleme; böylece tanılama bilgilerini geri kazanmak için asla bir mesaj dizesini ayrıştırmazsınız. - Mesajlar eyleme dönüştürülebilirdir: adlandırılmış kurucular, genel bir şablon yerine gerçek kök nedeni (ve çoğu zaman düzeltmeyi) mesaja bağlar.
- Her istisna sınıfı hangi rolün işlem yapabileceğini belgeler — geliştirici, altyapı veya kitaplık çağıranı — böylece önceliklendirme, yığın izini okumadan önce başlar.
NextPDF buna nasıl yaklaşır
“NextPDF buna nasıl yaklaşır” başlıklı bölümHiyerarşi sığdır ve bilinçli tasarlanmıştır. Tek bir temel, alana özgü türlerden oluşan bir katman ve her birinin uyduğu bir sözleşme vardır.
Tek temel, tasarım gereği toplu yakalama sağlar. NextPdfException soyuttur, RuntimeException sınıfını genişletir ve ContextAwareExceptionInterface arabirimini uygular:
abstract class NextPdfException extends RuntimeException implements ContextAwareExceptionInterface{ /** @return array<string, mixed> */ public function getContext(): array { return []; }}Soyut olması bilinçli bir karardır. Belirsiz temeli asla kazara yakalamazsınız, çünkü doğrudan hiç fırlatılmaz. Onu bir güvenlik ağı olarak bilinçli şekilde yakalarsınız; belirli bir işlem yapabildiğinizde de belirli bir alt sınıfı yakalarsınız.
Belirli, türlenmiş alt sınıflar. Eksik bir yazı tipi genel bir hata değildir; o bir FontNotFoundException nesnesidir ve işlem yapmak için ihtiyaç duyduğunuz verileri taşır:
final class FontNotFoundException extends NextPdfException{ public function __construct( private readonly string $fontName, private readonly array $searchPaths, private readonly bool $fallbackAttempted, ?Throwable $previous = null, ) { parent::__construct( \sprintf('Font "%s" not found. Searched: [%s].', $fontName, \implode(', ', $searchPaths)), 0, $previous, ); } // getFontName(), getSearchPaths(), wasFallbackAttempted(), getContext()}Mesaj, yazı tipini ve aranan tam yolları adlandırır. Hangi dizinin eksik olduğunu tahmin etmeniz gerekmez; istisna size söyler.
Yapılandırılmış bağlam, dize taraması değil. Her istisna, doğrudan bir günlüğe veya bir APM yüküne serileştirmek için güvenli olan, snake_case kullanan ve yalnızca ilkel değerlerden oluşan bir eşleme döndürür:
public function getContext(): array{ return [ 'config_key' => $this->configKey, 'given_value' => $this->givenValue, 'expected_type' => $this->expectedType, ];}Sözleşme amacını açıkça gösterir. Bir günlükleme ara yazılımı, $logger->error($e->getMessage(), $e->getContext()) çağrısını, mesajı hiç ayrıştırmadan herhangi bir NextPDF istisnası için yapabilir. Mesaj insanlar içindir. Bağlam makineler içindir. Hiçbirinin diğerinin işini yapması gerekmez.
Adlandırılmış kurucular aracılığıyla eyleme dönüştürülebilir mesajlar. Hataların rastlantısal olmaktan çıkıp tasarlanmış hale geldiği yer burasıdır. SignatureException yalnızca “B-LT düzeyinde imzalama başarısız oldu” demez. Gerçek kök nedeni ve çoğu zaman tam çözümü mesaja bağlayan adlandırılmış kurucular sunar:
public static function tsaUrlEmpty(string $signatureLevel): self{ return new self('', $signatureLevel, null, 'TSA endpoint URL is empty: pass a non-empty `tsaUrl` to the TsaClient ' . 'constructor (e.g. "https://timestamp.example.com/tsa") or remove the ' . 'TSA client wiring if no timestamping is required at this signature level');}Mesaj neyin yanlış olduğunu ve bu konuda ne yapılması gerektiğini belirtir. Eksik bir yetenek paketi, mevcut olmayan bir HTTP istemcisi, yanlışlıkla seçilmiş yalnızca özet üreten bir algoritma, algoritmayla eşleşmeyen bir anahtar türü ve daha fazlası için kardeş kurucular vardır. Her biri, bir başarısızlık sınıfını, geliştiricinin motorun kaynak kodunu okumadan üzerinde işlem yapabileceği bir cümleye dönüştürür.
Bilinçli olarak gürültülü olan başarısızlıklar. Bazı istisnalar tam da sessiz bir boşluğun gürültülü hale gelmesi için vardır. NotImplementedException, grep ile aranabilir bir feature etiketi ve bir followUp başvurusu taşır:
final class NotImplementedException extends NextPdfException{ public function __construct( public readonly string $feature, public readonly string $followUp, ?Throwable $previous = null, ) { parent::__construct( \sprintf('%s is not implemented in this release. %s', $feature, $followUp), 0, $previous, ); }}Ulaşılan ancak bağlanmamış bir yol, makul bir işlemsiz değer döndürmek yerine bunu fırlatır. Aynı fikir StrictModeViolation nesnesi için de geçerlidir: alt sınıfları, sapan yapı için kısa, grep ile aranabilir bir etiketin yanı sıra isteğe bağlı konum ve alıntı bağlamı taşır. Bir spesifikasyon sapması, sessizce yanlış bir işleme değil, türlenmiş, bağlamsal bir durdurmaya dönüşür.
Sınıfın kendisinde önceliklendirme meta verisi. Her istisna sınıfı, belge bloğunda kimin işlem yapabileceğini adlandırır. Örneğin, FontNotFoundException için bu “Geliştirici (yazı tipi yolunu doğrulayın) veya Altyapı (dosya izinlerini düzeltin)” şeklindedir. InvalidConfigException için bu “Geliştirici (NextPDF çağrılmadan önce yapılandırmayı düzeltin)” şeklindedir. NotImplementedException için bu “Kitaplık çağıranları — ya çağrıyı kaldırın ya da gelecekteki bir sürüme sabitleyin” şeklindedir. Önceliklendirme yığın izinden önce başlar, çünkü “bu benim sorunum mu yoksa operasyon ekibinin mi?” sorusunun yazılı yanıtı zaten vardır.
Tablo, tasarımı ve her özelliğin size ne kazandırdığını özetler.
| Tasarım özelliği | Kaynak kodda | Size ne kazandırır |
|---|---|---|
| Tek bir soyut temel | NextPdfException (soyut, bağlam arabirimini uygular) | Tüm kitaplık hatalarını tek bir türle yakalayın; belirsiz temeli kazara yakalamayın |
| Belirli türlenmiş alt sınıflar | FontNotFoundException, InvalidConfigException, SignatureException, … | Tam olarak ele alabileceğiniz başarısızlığı yakalayın |
| Yapılandırılmış bağlam | getContext() — yalnızca snake_case ilkel değerler | Bir mesaj dizesini ayrıştırmadan günlüğe yazın veya APM’ye gönderin |
| Eyleme dönüştürülebilir mesajlar | Adlandırılmış kurucular kök neden + çözümü bağlar | İşlem yapabileceğiniz bir cümle, bir şablon değil |
| Bilinçli olarak gürültülü | NotImplementedException, StrictModeViolation | Sessiz bir boşluk, türlenmiş, grep ile aranabilir bir durdurmaya dönüşür |
| Önceliklendirme meta verisi | Her sınıfın belge bloğunda “Actionable by:“ | Yığın izini okumadan önce bunun kimin sorunu olduğunu bilin |
Kanıtlar ne söylüyor
“Kanıtlar ne söylüyor” başlıklı bölümBu sayfa Evidence: Code-backed niteliğindedir: her sınıf, imza ve mesaj biçimi, yeniden ifade edilmeden motorun istisna ad alanından alıntılanmıştır.
- Soyut temel ve onun
ContextAwareExceptionInterfacesözleşmesi, türlenmiş alt sınıflar,getContext()biçimi veSignatureExceptionadlandırılmış kurucuları, kaynak koddan kelimesi kelimesine alıntılanmıştır. - “Actionable by:” önceliklendirme satırları, aynı dosyalardaki sınıf belge bloğu sözleşmeleridir.
- İnsan faktörleri dayanağı Spec: ISO 9241-110 ISO 9241-110 standardıdır — §5.6.4.3 düzeltilebilecek kadar açık hataları, §6 ise kullanım hatasına dayanıklılık ilkesini ele alır. Motor, geliştiriciyi kullanıcı olarak ve istisnayı söz konusu maddeleri karşılaması gereken arabirim olarak ele alır.
Pratik örnek
“Pratik örnek” başlıklı bölümBir güvenlik ağı olarak genel düzeyde yakalayın, işlem yapabileceğiniz yerde belirli düzeyde yakalayın ve yapılandırılmış bağlamı doğrudan günlükleme katmanınıza aktarın — mesaj ayrıştırması yok.
<?php
declare(strict_types=1);
use NextPDF\Core\Document;use NextPDF\Exception\FontNotFoundException;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
function renderInvoice(LoggerInterface $logger): ?string{ try { $document = Document::createStandalone(); $document->setTitle('Invoice 2026-0042'); $document->addPage(); $document->setFont('BrandSans', '', 12); $document->cell(0, 10, 'Thank you for your business.', newLine: true);
return $document->getPdfData(); } catch (FontNotFoundException $e) { // Specific: we can recover — fall back to a built-in font. // getContext() is log-safe structured data, not a parsed string. $logger->warning($e->getMessage(), $e->getContext());
return null; // caller re-renders with 'helvetica' } catch (NextPdfException $e) { // Backstop: any other NextPDF failure, still with structured context. $logger->error($e->getMessage(), $e->getContext());
return null; }}Belirli catch bloğu kurtarma yapar, çünkü istisna türü kurtarmanın mümkün olduğunu ona söyler. Güvenlik ağı, diğer tüm durumlar için yapılandırılmış bağlamı günlüğe yazar. Uygulama, ne olduğunu öğrenmek için hiçbir noktada mesajı ayrıştırmaz.
Yaygın yanlış anlama
“Yaygın yanlış anlama” başlıklı bölümYaygın yanlış yorum, derin bir istisna ağacının aşırı mühendislik olduğu ve tek bir hata türünün daha basit olacağıdır. Bu, motor için daha basit ve sizin için daha kötü olurdu. Tek bir tür, her başarısızlığın genel bir yığın izi olduğu ve kurtarma mantığının bir dize eşleşmesi olduğu anlamına gelir. O eşleşme kırılgandır; bir sonraki mesajın yeniden ifade edilmesi onu bozar. Küçük, belirli bir hiyerarşi, o bilgiyi tür sistemine taşır; orada derleyici ve catch bloklarınız onu kullanabilir.
İkinci bir yanlış anlama, mesajın ve bağlamın gereksiz olduğudur. Gereksiz değillerdir. Mesaj, bir günlük satırını okuyan bir insan için düz metindir. Bağlam, kodu yönlendirme, uyarı verme veya panolar için türlenmiş bir eşlemedir. Bunları birbirine karıştırmak, tam olarak getContext() sözleşmesinin ortadan kaldırmak için var olduğu dize ayrıştırma tuzağıdır.
Sınırlar ve kapsam
“Sınırlar ve kapsam” başlıklı bölümHiyerarşi bilinçli olarak sığdır. NextPDF, akla gelebilecek her başarısızlık için ayrı bir istisna sınıfı oluşturmaz. O başarısızlığı özellikle yakalamak, bir çağıranın makul biçimde yapacağı bir şey olduğunda bir tane oluşturur. Aşırı bölmek, dize ayrıştırma sorununu giderek büyüyen bir yakalama listesi sorunuyla değiş tokuş ederdi.
getContext(), günlükler ve APM için tasarlanmıştır; bu nedenle sözleşme gereği yalnızca ilkel değerler ve ilkel değer listeleri döndürür, iç içe nesneler döndürmez. Bu, tanılama bağlamıdır; motorun iç bileşenlerinin serileştirilmiş bir anlık görüntüsü değildir. Ayrıca, üzerine harici şemalar inşa edilecek kararlı bir tel biçimi de değildir.
Bu sayfa istisna tasarım yüzeyini açıklar. İstisnaların eksiksiz kümesi ve alanları motorla birlikte gelişir. Burada alıntılanan sınıflar ve biçimler bu inceleme itibarıyla günceldir; dondurulmuş bir katalog değil, sözleşmeyi gösteren örneklerdir. Sözleşme — tek temel, türlenmiş alt sınıflar, yapılandırılmış bağlam, eyleme dönüştürülebilir mesajlar — kararlı olan kısımdır.
İlgili belgeler
“İlgili belgeler” başlıklı bölüm- Tahmin etmeyi reddeden bir API — en başta bu istisnaları fırlatan hızlı başarısız olma korumaları.
- NextPDF tasarım felsefesi — “hatalar bir API yüzeyidir” ilkesinin neden birinci sınıf bir ilke olduğu.
- İşlem hattı modeli — bir belge motorun içinden geçerken bu başarısızlıkların nerede ortaya çıktığı ve nasıl gözlemlendikleri.
Sözlük
“Sözlük” başlıklı bölüm- Koda dayalı (kanıt düzeyi) — iddiaları, yeniden ifade edilmek yerine alıntılanarak motorun kendi kaynak koduyla denetlenen bir sayfa.
- Bağlama duyarlı istisna — NextPDF istisnası olup
ContextAwareExceptionInterfacearabirimini uygulayan vegetContext()yöntemini açığa çıkaran bir istisna. Söz konusu yöntem, mesaj dizesini ayrıştırmadan bir günlüğe veya APM yüküne serileştirmek için güvenli, ilkel tanılama alanlarından oluşan bir snake_case eşleme döndürür. - Adlandırılmış kurucu — bir mesajı belirli bir kök nedene ve çoğu zaman onun çözümüne bağlayarak bir istisna oluşturan statik bir fabrika yöntemi (örneğin
SignatureException::tsaUrlEmpty()). - PAdES — PDF Advanced Electronic Signatures, PDF imzalama için ETSI profil ailesi. İlk kullanımda açılımı verilir; imzalama sayfalarında ayrıntılı olarak ele alınır.
- TSA — Time-Stamping Authority, daha yüksek PAdES profilleri tarafından kullanılan RFC 3161 zaman damgalarını veren güvenilir hizmet.