معالجة الأخطاء وفق التسلسل الهرمي للاستثناءات في NextPDF
لمحة سريعة
قسم بعنوان «لمحة سريعة»يطرح NextPDF استثناءات محدَّدة النوع عند وقوع حالات استثنائية، ولا يُخفي أي خطأ خلف قيمة مُعادة false أو null. يرث كل استثناء خاص بالنطاق القاعدة المجردة نفسها، NextPdfException، ويُوفّر سياقًا تشخيصيًا منظَّمًا عبر ContextAwareExceptionInterface. يوضّح هذا الدليل مواضع التقاط الاستثناءات، وكيفية تسجيل السياق المنظَّم في مسار مراقبة أداء التطبيقات (APM). كما يبيّن الإخفاقات التي لا تغطيها كتلة الالتقاط الشاملة الواحدة.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/core:^3لا تحتاج إلى أي امتداد إضافي.
نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»يكون التسلسل الهرمي على النحو الآتي:
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\OracleConformanceFailureتترتب على هذا التسلسل الهرمي نتيجتان عمليتان، وقد جرى التحقق من كلتيهما بمقارنة الكود المصدري:
- يلتقط
catch (NextPdfException $e)كل استثناء ضمنNextPDF\Exception، بما في ذلك انتهاكات الوضع الصارم. فكلها ترث القاعدة المجردة. - لا يلتقط كل ما قد تطرحه المكتبة. يرث
NextPDF\Support\DegradedExceptionمباشرةً منRuntimeException، وليس منNextPdfException. لذلك فإنcatch (NextPdfException $e)لا يلتقط رفض سياسة التدهور. للتعامل معه، التقطDegradedException(أوRuntimeExceptionالأوسع) صراحةً. يوضح هذا الدليل ذلك الحد بدلًا من افتراض أن كتلة التقاط شاملة واحدة توفر تغطية كاملة.
يعيد NextPdfException::getContext() قيمة array<string, mixed> بمفاتيح بنمط snake_case وقيم أولية فقط، أو قوائم من القيم الأولية. يمكنك تسلسلها مباشرةً ضمن مصفوفة السياق الخاصة بمُسجِّل PSR-3. يضع PSR-3 §1.3 الاستثناء تحت مفتاح السياق 'exception'. يضيف getContext() في NextPDF تفاصيل نطاقية بجوار ذلك المفتاح، لا كائن الاستثناء نفسه.
واجهة API
قسم بعنوان «واجهة API»تستند واجهة API هذه إلى توثيق PHPDoc في NextPDF\Exception\NextPdfException، وNextPDF\Contracts\ContextAwareExceptionInterface، والاستثناءات النطاقية الملموسة (مثل NextPDF\Exception\FontNotFoundException، مع getFontName() / getSearchPaths() / wasFallbackAttempted())، وNextPDF\Support\DegradedException (الذي يحمل Capability وDegradationPolicy). تستخدم الأمثلة أدناه NextPdfException::getContext() ودوال الوصول الخاصة بكل استثناء.
مثال برمجي — بداية سريعة
قسم بعنوان «مثال برمجي — بداية سريعة»<?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());}مثال برمجي — بيئة الإنتاج
قسم بعنوان «مثال برمجي — بيئة الإنتاج»يعرض المثال الكامل كتل الالتقاط الدقيقة، وتسجيل السياق المنظَّم، والحدّ الذي تمثله DegradedException. ويحافظ أيضًا على قناة إخراج بيئة التشغيل.
<?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 متاحًا لبيئة التشغيل، ولا يُكتب ملف PDF إلا إلى NEXTPDF_COOKBOOK_OUTPUT.
الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- رتّب كتل الالتقاط من الأخص إلى الأعم. تطابق PHP أول كتلة
catchمتوافقة. إذا وضعتcatch (NextPdfException $e)قبلcatch (FontNotFoundException $e)فستجعل الكتلة الأخص كودًا ميتًا. DegradedExceptionليس من نوعNextPdfException. وفقًا للتحقق من الكود المصدري، فهو يرثRuntimeException. إذا استُخدمcatch (NextPdfException $e)وحده، فسيترك رفض التدهور الصارم ينتشر. التقطه (أوRuntimeException) صراحةً عندما تكون سياسة التدهور قيد العمل.getContext()آمن لأنظمة APM بموجب العقد. المفاتيح بنمط snake_case. والقيم أولية أو قوائم من القيم الأولية، من دون كائنات متداخلة أو موارد. يمكنك تسلسلها مباشرةً، ولا يحتوي السياق أبدًا على بايتات المستند.- لا تُحلِّل رسائل الاستثناءات. الرسائل موجّهة للبشر وقابلة للتغيير. استخدم دوال الوصول المُحدَّدة النوع (
getFontName()، وcapability->id، وما شابه) وgetContext()بوصفها الواجهة الآلية المستقرة. - تنبيه بشأن الأرقام القديمة. قد تستشهد المواد الأقدم بعدد ثابت من “استثناءات النطاق N”. يتسع التسلسل الهرمي عبر الإصدارات. اعتمد على النوع الأساسي
NextPdfExceptionوعلىinstanceof، ولا تعتمد أبدًا على عدد ثابت مُضمَّن في الكود. - أبقِ عناصر PSR-3 النائبة ضمن سلاسل نصية. عند التسجيل، أبقِ الرسالة سلسلة نصية تحتوي رموز
{placeholder}، وضع القيم في مصفوفة السياق (PSR-3 §1.2). لا تُدرِج كائن الاستثناء داخل الرسالة.
الأداء
قسم بعنوان «الأداء»لا تضيف معالجة الاستثناءات أي تكلفة في الحالة الطبيعية. لا يطرح NextPDF استثناءات إلا في الحالات الاستثنائية، ويبني getContext() مصفوفة صغيرة عند الطلب. تنطبق ميزانية performance_budget (wall_ms: 2000، peak_mb: 96) على تشغيل بيئة هذا الدليل، لا على المستندات العشوائية.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»- صُمِّم
getContext()ليكون آمنًا للتسجيل: قيم أولية فقط، من دون حمولة المستند أو بايتات الملف. ومع ذلك، تظل مسؤولًا عن القيم التي تضيفها إلى سياق السجل. نقِّ أي قيمة يقدّمها المستخدم (مثل مسار ملف) وفق سياسة التسجيل لديك قبل أن تصل إلى مَصرِف السجل. - لا تَعرِض رسائل الاستثناءات الخام للمستخدمين النهائيين بطريقة تكشف بنية نظام الملفات. اعرض رسالة عامة، وسجِّل السياق المنظَّم من جهة الخادم.
المطابقة
قسم بعنوان «المطابقة»| العبارة | المواصفة | البند | reference_id |
|---|---|---|---|
يُدرَج الاستثناء في سياق سجل PSR-3 تحت المفتاح exception. | PSR-3 | §1.3 | |
| تبقى رسائل السجل سلاسل نصية، وتطابق أسماء العناصر النائبة مفاتيح السياق. | PSR-3 | §1.2 | |
| يُعاد توليد تاريخ التعديل مع كل عملية حفظ، لذا فإن المُخرَج مستقر بنيويًا (لا بحسب البايتات). | ISO 32000-2 | §14.3 |
يُتحقَّق من هذا الدليل باستخدام ملف تعريف قابلية إعادة الإنتاج البنيوي. يحمل المُخرَج في المُذيَّل قيمة /ID وتاريخ تعديل يُعاد توليدهما مع كل عملية حفظ، لذلك يتعذّر تحقيق تطابق على مستوى البايتات. تبقى البنية المُطبَّعة بأداة qpdf مستقرة.