Özel hata kurtarma ve yeniden deneme stratejilerini uygulayın
Bir bakışta
“Bir bakışta” başlıklı bölümÜretim ortamındaki bir belge hizmeti, bir istisnayı yakalayıp günlüğe yazmakla yetinmez. Sonrasında ne yapacağına karar verir: kademe düşürülmüş çıktıyla devam etmek, ikinci bir işleme yoluna geçmek, motorun kabul ettiği girdiyle yeniden denemek veya hatadan önce oluşturulan sayfaları teslim etmek. Bu tarif, NextPDF’in istisna hiyerarşisi ve belge durumunu denetleme yöntemleri üzerine kurulu dört kurtarma stratejisini gösterir:
- Yazı tipi hatasında denetimli kademe düşürme —
NextPDF\Exception\FontNotFoundExceptionyakalayın, garantili bir yazı tipine geri dönün ve belgeyi oluşturmaya devam edin. - Yedek işleyici — süreç içi
Document::writeHtml()yolu girdiyi reddettiğinde,Document::writeHtmlChrome()ile, yaninextpdf/artisanChrome köprüsü üzerinden yeniden deneyin. - Alternatif HTML ile yeniden deneme —
NextPDF\Exception\HtmlParsingExceptionveyaNextPDF\Exception\CssResolutionBudgetExceededExceptionoluştuğunda, basitleştirilmiş ve çalıştığı bilinen bir HTML çeşidiyle yeniden deneyin. - Kısmi belge kurtarma — bir hatadan sonra
Document::getNumPages()okuyun ve o ana kadar oluşturulan içeriği atmak yerine kaydedin.
Hangi düzeyde yakalama yapmanız gerektiğini zaten biliyorsunuz. Eşlik eden NextPDF istisna hiyerarşisiyle hataları işleyin sayfası hiyerarşinin kendisini kapsar. Bu sayfa ise yakalamadan sonra ne yapacağınızı gösterir.
Bu tarif, açık kaynak yazılım (OSS) olan core sürümünü hedefler. Burada adı geçen her API nextpdf/core içinde bulunur. Tek isteğe bağlı bağımlılık, Chrome yedeği için nextpdf/artisan paketidir.
Kurulum
“Kurulum” başlıklı bölümcomposer require nextpdf/core:^3Yedek işleyici stratejisi ayrıca Chrome köprüsünü kullanır:
composer require nextpdf/artisanPaket nextpdf/artisan bulunmadığında, Document::writeHtmlChrome() işlemek yerine NextPDF\Exception\PageLayoutException fırlatır. Aşağıdaki yedek stratejisi, eksik bir köprüyü kurtarılabilir başka bir durum olarak ele alır.
Kavramsal genel bakış
“Kavramsal genel bakış” başlıklı bölümKurtarma, NextPDF hakkında her ikisi de kaynak üzerinden doğrulanmış iki gerçeğe dayanır.
İstisna hiyerarşisi, neyin kurtarılabilir olduğunu gösterir. Etki alanına özgü her istisna, soyut temel sınıf NextPDF\Exception\NextPdfException sınıfını genişletir; bu sınıf da RuntimeException sınıfını genişletir ve NextPDF\Contracts\ContextAwareExceptionInterface arabirimini uygular. İlgili hata için bir kurtarma yolu seçmek üzere belirli bir alt türü yakalayın:
FontNotFoundExceptionşu bilgileri taşır:getFontName(),getSearchPaths()vewasFallbackAttempted()— farklı bir yazı tipiyle yeniden denemek için yeterlidir.HtmlParsingExceptionşu bilgileri taşır:getRule(),getPosition()vegetHtmlSnippet()— basitleştirilmiş bir yeniden denemenin değip değmeyeceğine karar vermek için yeterlidir.CssResolutionBudgetExceededExceptionşu bilgileri taşır:getVisits()vegetBudget()— sadeleştirilmiş bir stil sayfasının patolojik bir seçiciyi giderebileceğine işaret eder.- Önemli bir sınır:
NextPDF\Support\DegradedException,RuntimeExceptionsınıfını doğrudan genişletir,NextPdfExceptionsınıfını değil. Bu nedenlecatch (NextPdfException $e), kademe düşürme ilkesi kaynaklı bir reddi yakalamaz. EtkinNextPDF\Contracts\DegradationPolicyilkesiStrictveyaBalancedolduğunda, bu durumdan kurtulmak içinDegradedExceptionistisnasını açıkça yakalayın.
Belge, siz onu oluştururken denetlenebilir. Bir Document, oluşturma durumunu salt okunur erişimcilerle sunar. getNumPages(), etkin ve henüz boşaltılmamış sayfa dahil olmak üzere toplam sayfa sayısını döndürür ve getPage(), geçerli sayfanın sıfır tabanlı dizinini döndürür. Oluşturma sırasında oluşan bir hatadan sonra, tamamlanmış sayfa olup olmadığını öğrenmek için getNumPages() okuyun, ardından bunları dışarı aktarmak için save() veya getPdfData() çağırın. Motor ayrıca ölümcül olmayan kademe düşürme olaylarını da kaydeder: getWarnings() bir list<NextPDF\Support\Warning> döndürür, hasWarnings() bunlardan herhangi birinin toplanıp toplanmadığını bildirir ve hasDegradedParity() çıktı doğruluğunun etkilenip etkilenmediğini bildirir. Bu yöntemler, bir kurtarma rutininin istisnayı ayrıştırmadan “temiz biçimde başarılı oldu” ile “azaltılmış doğrulukla başarılı oldu” durumlarını ayırt etmesine olanak tanır.
Kademe düşürme ilkesi, hangi olayları istisna olarak, hangilerini uyarı olarak işleyeceğinizi denetler. NextPDF\Core\Config varsayılan olarak DegradationPolicy::Balanced kullanır; bu ilke sınırlı kademe düşürmelerde uyarı üretip devam eder, ancak engelleyici bir etki olduğunda fırlatır. DegradationPolicy::Permissive asla fırlatmaz ve her şeyi uyarı kanalında toplar. DegradationPolicy::Strict herhangi bir uyumluluk riskinde, anlamsal kayıpta veya engelleyici etkide fırlatır. Önce ilkeyi seçin, ardından o ilkenin ürettiği hata biçimleri için kurtarma yazın.
API yüzeyi
“API yüzeyi” başlıklı bölümAşağıdaki kurtarma kodu şu doğrulanmış üyeleri kullanır:
NextPDF\Core\Document::createStandalone(?Config $config = null): self,addPage(),setFont(string $family, string $style = '', float $size = 12.0): static,cell(...),writeHtml(string $html): static,writeHtmlChrome(string $html, ?float $width = null, ?float $height = null): static,save(string $path): void,getPdfData(): string,getNumPages(): int,getPage(): int,getWarnings(): list<Warning>,hasWarnings(): bool,hasDegradedParity(): bool,addFontDirectory(string $directory): static.NextPDF\Core\Config::withDegradationPolicy(DegradationPolicy $policy): selfvedegradationPolicyvarsayılanıDegradationPolicy::Balanced.NextPDF\Contracts\DegradationPolicy—Strict,Balanced,Permissive.NextPDF\Exception\NextPdfException(soyut temel sınıf),NextPDF\Exception\FontNotFoundException,NextPDF\Exception\HtmlParsingException,NextPDF\Exception\CssResolutionBudgetExceededException,NextPDF\Exception\WriterException,NextPDF\Exception\PageLayoutException.NextPDF\Support\DegradedException(capabilityvepolicytaşıyan),NextPDF\Support\Capability(id,status,reason,isDegraded()),NextPDF\Support\Warning,NextPDF\Support\WarningSeverity.
Kod örneği — hızlı başlangıç
“Kod örneği — hızlı başlangıç” başlıklı bölümEn küçük işe yarar kurtarma, eksik bir yazı tipi hatasını yakalar, garantili bir yazı tipine geri döner ve devam eder. Bu parça, üretim örneğindeki daha geniş işleme mantığını kapsamaz. Günlük kaydı ve DegradedException sınırını içeren eksiksiz bir işleyici için aşağıdaki üretim örneğini okuyun.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\FontNotFoundException;
$doc = Document::createStandalone();$doc->addPage();
try { // A face that may not be installed on every host. $doc->setFont('CorporateSans', '', 12);} catch (FontNotFoundException $e) { // Recover: fall back to a face the engine always resolves. $doc->setFont('helvetica', '', 12);}
$doc->cell(0, 10, 'Rendered with a recovered font.', newLine: true);$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf');Kod örneği — üretim
“Kod örneği — üretim” başlıklı bölümTam örnek, dört stratejinin tümünü tek bir işleme hattında birleştirir: yazı tipi yedeği, süreç içi yoldan Chrome’a geçen işleyici yedeği, alternatif HTML yeniden denemesi ve getNumPages() tarafından yönlendirilen kısmi belge kurtarma. Harness, çıktı kanalı sözleşmesine uyar ve hiçbir zaman çıplak bir Exception yakalamaz veya bir catch bloğunu boş bırakmaz.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\ContextAwareExceptionInterface;use NextPDF\Contracts\DegradationPolicy;use NextPDF\Core\Config;use NextPDF\Core\Document;use NextPDF\Exception\CssResolutionBudgetExceededException;use NextPDF\Exception\FontNotFoundException;use NextPDF\Exception\HtmlParsingException;use NextPDF\Exception\NextPdfException;use NextPDF\Exception\PageLayoutException;use NextPDF\Exception\WriterException;use NextPDF\Support\DegradedException;
/** * A minimal structured sink. In production this is your PSR-3 logger; the * exception class and its structured context become log fields. * * @param array<string, mixed> $context */function logRecovery(string $message, array $context): void{ fwrite(STDERR, $message . ' ' . json_encode($context, JSON_THROW_ON_ERROR) . "\n");}
/** * Resolve a usable font, degrading from the requested face to a guaranteed * fallback. Returns the face actually applied so the caller can record it. * * @param non-empty-string $requested * @param non-empty-string $fallback * * @return non-empty-string */function applyFontWithFallback(Document $doc, string $requested, string $fallback): string{ try { $doc->setFont($requested, '', 12);
return $requested; } catch (FontNotFoundException $e) { // STRATEGY 1 — graceful degradation on a font failure. logRecovery('Font unavailable; degrading to a guaranteed face', [ 'exception' => $e::class, 'font_name' => $e->getFontName(), 'searched' => $e->getSearchPaths(), 'fallback' => $fallback, ]); $doc->setFont($fallback, '', 12);
return $fallback; }}
/** * Render HTML through the in-process pipeline, then through the Chrome bridge, * then through a simplified HTML variant. Each layer recovers a more specific * failure than the last. */function renderHtmlWithRecovery(Document $doc, string $primaryHtml, string $simplifiedHtml): void{ try { // Primary path: the in-process HTML/CSS pipeline. $doc->writeHtml($primaryHtml);
return; } catch (CssResolutionBudgetExceededException $e) { // STRATEGY 3 — retry with alternative HTML for a pathological selector. logRecovery('CSS resolution budget exceeded; retrying with simplified HTML', [ 'exception' => $e::class, 'visits' => $e->getVisits(), 'budget' => $e->getBudget(), ]); $doc->writeHtml($simplifiedHtml);
return; } catch (HtmlParsingException $e) { // STRATEGY 2 — fall back to the Chrome renderer for input the // in-process parser rejects. The Chrome bridge uses a browser CSS // engine, so it may accept what the in-process parser would not. logRecovery('In-process HTML parse failed; trying the Chrome fallback renderer', [ 'exception' => $e::class, 'rule' => $e->getRule(), 'position' => $e->getPosition(), ]);
try { $doc->writeHtmlChrome($primaryHtml);
return; } catch (PageLayoutException $chromeError) { // The Chrome bridge is absent (nextpdf/artisan not installed) or // rejected the input. Last resort: the simplified HTML variant // through the in-process pipeline. logRecovery('Chrome fallback unavailable; retrying with simplified HTML', [ 'exception' => $chromeError::class, ]); $doc->writeHtml($simplifiedHtml);
return; } }}
// --- Configure the degradation policy up front ---------------------------// Balanced (the default) warns on bounded degradation and throws only on a// blocking impact. A regulated workflow would choose DegradationPolicy::Strict.$config = (new Config())->withDegradationPolicy(DegradationPolicy::Balanced);$doc = Document::createStandalone($config);
$primaryHtml = '<h1>Quarterly report</h1><p>Body paragraph with rich styling.</p>';$simplifiedHtml = '<h1>Quarterly report</h1><p>Body paragraph (simplified).</p>';
$outputPath = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/out.pdf';
try { $doc->addPage(); $applied = applyFontWithFallback($doc, 'CorporateSans', 'helvetica'); $doc->cell(0, 12, 'Custom error recovery patterns', newLine: true);
renderHtmlWithRecovery($doc, $primaryHtml, $simplifiedHtml);
$doc->save($outputPath);
logRecovery('Document built', [ 'font_applied' => $applied, 'pages' => $doc->getNumPages(), 'has_warnings' => $doc->hasWarnings(), 'degraded_parity' => $doc->hasDegradedParity(), ]);} catch (DegradedException $e) { // BOUNDARY: DegradedException extends RuntimeException directly, NOT // NextPdfException, so the catch-all below would not have caught it. // Under Strict/Balanced policy a blocking degradation lands here. logRecovery('Capability degraded under the active policy; emitting a built partial', [ 'exception' => $e::class, 'capability' => $e->capability->id, 'status' => $e->capability->status->value, 'reason' => $e->capability->reason ?? 'unknown', 'policy' => $e->policy->value, ]); // STRATEGY 4 — partial-document recovery: save whatever pages exist. if ($doc->getNumPages() > 0) { $doc->save($outputPath); }} catch (WriterException $e) { // Serialization or I/O failure: the in-memory document is valid but could // not be written. Surface the stage so infrastructure can act on it. logRecovery('PDF write failed; document was valid in memory', [ 'exception' => $e::class, 'writer_state' => $e->getWriterState(), 'output_path' => $e->getOutputPath(), ]);} catch (NextPdfException $e) { // Catch-all for every other NextPDF\Exception\*. STRATEGY 4 again: if any // complete pages were built before the failure, emit them rather than // discarding the work. $context = ['exception' => $e::class, 'pages' => $doc->getNumPages()]; if ($e instanceof ContextAwareExceptionInterface) { $context += $e->getContext(); } logRecovery('Unrecovered NextPDF failure; attempting a partial save', $context); if ($doc->getNumPages() > 0) { $doc->save($outputPath); }}
fwrite(STDERR, "Recovery pipeline complete.\n");STDOUT, harness için boş kalır. Kurtarma tanılamaları STDERR kanalına gider ve PDF dosyası yalnızca NEXTPDF_COOKBOOK_OUTPUT konumuna yazılır.
Sınır durumları ve tuzaklar
“Sınır durumları ve tuzaklar” başlıklı bölüm- catch bloklarını özelden genele doğru sıralayın. PHP, ilk uyumlu
catchbloğuyla eşleşir.catch (NextPdfException $e)bloğunucatch (WriterException $e)bloğundan önce yerleştirmek, özel bloğu ulaşılamaz hale getirir; çünküWriterException,NextPdfExceptionsınıfını genişletir. DegradedExceptionhiyerarşinin dışında yer alır.RuntimeExceptionsınıfını genişletir,NextPdfExceptionsınıfını değil. YalnızcaNextPdfExceptionyakalayan bir iş hattı, katı ilke kaynaklı bir reddin yakalanmadan yayılmasına izin verir. Varsayılan olmayan bir kademe düşürme ilkesi etkin olduğundaDegradedException(veya daha geniş birRuntimeException) yakalayın.- Yedek yazı tipi de başarısız olabilir. Yedek yazı tipiniz de kayıtlı değilse, ikinci
setFont()çağrısı yeniden fırlatır. Motorun bir dosya sistemi araması yapmadan çözdüğühelveticagibi bir Base14 takma adı kullanın veya yedeği garanti altına almak için baştaaddFontDirectory()ile paketlenmiş bir yazı tipi kaydedin. getNumPages()etkin ve boşaltılmamış sayfayı sayar. Bir sayfa açıkken, boşaltılmış sayfa sayısına bir eklenmiş değeri döndürür. Bir “kısmi kaydetme”, hata oluştuğunda oluşturulmakta olan sayfayı içerir; bu genellikle istediğiniz şeydir. Yalnızca tamamen tamamlanmış sayfalara ihtiyacınız varsa, ayrıcagetPage()üzerinde dallanma yapın.- Chrome yedeği yalnızca kullanılabilirliği değil, doğruluğu da değiştirir. Süreç içi yol ve Chrome köprüsü farklı yerleşim motorları kullanır, dolayısıyla Chrome’a geri dönen bir belge farklı görünebilir. Yedeği şeffaf bir ikame olarak değil, bir kurtarma olarak ele alın ve çıktıyı hangi yolun ürettiğini kaydedin.
- Bir yeniden deneme, çalıştığı bilinen girdiyi kullanmalıdır. Basitleştirilmiş HTML yeniden denemesi yalnızca basitleştirilmiş çeşidin gerçekten daha basit olduğu durumda işe yarar: daha az iç içe seçici içermeli ve çözümleme bütçesini tüketen
:has()zincirleri barındırmamalıdır. Zaten başarısız olmuş aynı girdiyle yeniden denemek, aynı istisnada döngüye girer. - Temiz bir çalıştırmadan sonra uyarıları inceleyin. İstisna fırlatmadan tamamlanan bir işleme, yine de kademe düşürmeyle tamamlanmış olabilir. Çıktıyı piksel düzeyinde sadık kabul etmeden önce
hasDegradedParity()denetleyin vegetWarnings()okuyun;DegradationPolicy::Permissivealtında her kademe düşürme bir uyarıdır, asla bir istisna değildir.
Performans
“Performans” başlıklı bölüm- Kurtarma yalnızca hata yolunda maliyet ekler. NextPDF istisnai durumlarda fırlattığından, sorunsuz bir işleme çevresindeki
try/catchiçin ek maliyet üstlenmez. - İşleyici yedeği işlemeyi yeniden çalıştırır. Süreç içi deneme atılır ve Chrome denemesi sıfırdan başlar, dolayısıyla yedek işleme en kötü durumda her iki işleme süresine ek olarak Chrome’a süreçler arası gidiş dönüş maliyetine mal olur. İstek zaman aşımı değerlerini ayarlarken bunu hesaba katın.
- Alternatif HTML yeniden denemesi ikinci bir belgeyi ayrıştırır. Yeniden denemenin birincil denemeye göre ucuz kalması için basitleştirilmiş çeşidi küçük tutun.
- Kısmi kaydetme, halihazırda oluşturulmuş sayfaları seri hale getirir. Maliyeti, başarısız olan işe göre değil, hayatta kalan sayfa sayısına göre ölçeklenir.
Güvenlik notları
“Güvenlik notları” başlıklı bölüm- Ham istisna iletilerini veya dosya sistemi yollarını son kullanıcılara göstermeyin. Bir
FontNotFoundExceptioniletisi aranan dizinleri içerir ve birWriterExceptionçıktı yolunu içerir; her ikisi de sunucu dizin yapısını sızdırır. Yapılandırılmış bağlamı sunucu tarafında günlüğe yazın ve çağırana genel bir ileti döndürün. - Yeniden denenen HTML’yi her denemede güvenilmeyen girdi olarak ele alın. Yedek yol ve basitleştirilmiş HTML yeniden denemesi aynı girdi sınırından geçer; süreç içi yol ve Chrome köprüsü her biri kendi HTML güvenlik ilkesini uygular ve yeniden deneme bu doğrulamayı gevşetmez. Bir “basitleştirilmiş” çeşidi, sırf siz yazdınız diye daha güvenli kabul etmeyin.
- Kısmi kaydetme yine de dosya yazar. Eksiksiz bir çıktıya uyguladığınız aynı yol doğrulamasını, izinleri ve depolama konumu kurallarını kısmi çıktıya da uygulayın.
Document::save()akış sarmalayıcılarını ve boş baytları reddeder ve yol geçişini engellemek için üst dizini çözer, ancak ilettiğiniz hedef sizin sorumluluğunuzdadır.
Uyumluluk
“Uyumluluk” başlıklı bölümBu tarif normatif bir standart iddiasında bulunmaz. NextPDF’in genel istisna ve belge denetleme API’lerini kurtarma denetim akışına dönüştürür; ISO 32000-2 veya başka herhangi bir standart tarafından tanımlanan davranışı öne sürmez, dolayısıyla hiçbir citations: bloğu taşımaz.
Bu sayfa anlamsal yeniden üretilebilirlik profiliyle doğrulanır. Kurtarılan belge, her kaydetmede yeniden oluşturulan bir fragman /ID ve değişiklik tarihi taşır, dolayısıyla bayt özdeşliği elde edilemez. Yapısal soyut sözdizimi ağacı (AST) ve yalnızca üst veri karşılaştırması, çalıştırmalar arasında kararlı kalır.
Ayrıca bakınız
“Ayrıca bakınız” başlıklı bölüm- NextPDF istisna hiyerarşisiyle hataları işleyin — yakalama ayrıntı düzeyi ve yapılandırılmış bağlam; bu sayfanın üzerine kurulduğu temel.
- Exception modülü — tam istisna başvurusu.
- Support modülü —
DegradedException,Capability,Warningve kademe düşürme türleri. - Config modülü — kademe düşürme ilkesi yapılandırması.
- PDF’leri uzun süre çalışan bir işçide güvenli biçimde işleyin — paylaşılan kayıt defterlerini yeniden kullanan bir işçide kurtarma.