استكشاف أخطاء compat-legacy وإصلاحها
لمحة سريعة
قسم بعنوان «لمحة سريعة»تندرج معظم مشكلات الترحيل ضمن مجموعة محدودة من الأنماط. يوضّح كل بند أدناه العَرَض والسبب والإصلاح. إذا لم تكن متأكداً من أسلوب معيّن، فراجِع /integrations/tcpdf-compat/method-coverage/ ومصفوفة المرجع المعتمَدة داخل المستودع docs/TCPDF_COVERAGE.md.
كانت العملية تتوقف عند خطأ في PDF؛ والآن يفلت استثناء
قسم بعنوان «كانت العملية تتوقف عند خطأ في PDF؛ والآن يفلت استثناء»العَرَض. الشيفرة التي كانت تتوقف عند عرض معطوب أصبحت ترمي RuntimeException غير ملتقَط، فيُبلِغ الطلب أو المهمة عن خطأ.
السبب. تستدعي استدعاءات Error() في TCPDF القديم die(). أمّا المهايئ فيرمي RuntimeException بدلاً من ذلك، بحكم التصميم، حتى تكون الإخفاقات قابلة للرصد.
الإصلاح. غلِّف نقاط دخول العرض داخل try/catch، واربط الاستثناء بعقد معالجة الأخطاء لديك. لا تُعِد سلوك die(). راجِع /integrations/tcpdf-compat/production-usage/ § معالجة الإخفاقات.
new \TCPDF() ما زال يتحلّل إلى مكتبة TCPDF الأصلية
قسم بعنوان «new \TCPDF() ما زال يتحلّل إلى مكتبة TCPDF الأصلية»العَرَض. فعّلتَ LegacyBootstrap::enableAliases()، لكنّ الخرج ما زال يبدو مثل TCPDF القديم، أو لم يتغيّر السلوك.
السبب. يسجّل enableAliases() اسماً بديلاً فقط عندما لا يكون هناك صنف بهذا الاسم مُعرَّفاً مسبقاً. إذا بقي tecnickcom/tcpdf قابلاً للتحميل التلقائي وحُمِّل صنف \TCPDF الخاص به أولاً، فسيُتخطّى الاسم البديل، وتظلّ شيفرتك تستخدم TCPDF القديم.
الإصلاح. أثناء الترحيل، استخدِم استيرادات صريحة في كل ملف (use NextPDF\Compat\Tcpdf\TCPDF;) حتى يكون كل موضع استدعاء واضحاً بلا لبس. أزِل tecnickcom/tcpdf بعد نجاح التدقيق (راجِع /integrations/tcpdf-compat/migration/ المرحلة 5). لا تُشغِّل المكتبتين معاً مع تفعيل الأسماء البديلة العامة في العملية نفسها.
الأسلوب “يعمل” لكنّ المُعامِل الذي مرّرتُه يُتجاهَل
قسم بعنوان «الأسلوب “يعمل” لكنّ المُعامِل الذي مرّرتُه يُتجاهَل»العَرَض. ينجح الاستدعاء وينتج ملف Portable Document Format (PDF)، لكن خياراً مرّرتَه (رابط صورة، محاذاة، نقاط لكل بوصة (DPI)، لون إشارة مرجعية، …) لا يُحدِث أي أثر.
السبب. يقع الأسلوب ضمن مجموعة التجاهل الصامت. يقبل المُعامِل لأجل التوافق على مستوى الشيفرة المصدرية، ثم يُسقِطه. هذا سلوك موثَّق وليس عِلّة؛ راجِع /integrations/tcpdf-compat/method-coverage/ §2.
الإصلاح. شغِّل تدقيقاً بالوضع الصارم للعثور على كل استدعاء من هذا النوع:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->setStrictMode(true);$pdf->AddPage();$pdf->SetFont('helvetica', '', 12);
try { $pdf->Image('logo.png', 10, 10, 50, 0, '', 'https://example.com');} catch (TcpdfNotImplementedException $e) { // Message lists every ignored parameter and a migration hint. echo $e->getMessage(), "\n";}ثم أسقِط المُعامِل، أو أعد التعبير عنه عبر الواجهة البرمجية الحديثة ($pdf->getDocument())، كما هو موضّح في /integrations/tcpdf-compat/migration/ المرحلة 4.
القيمة المُعادة من MultiCell() هي دائماً 1
قسم بعنوان «القيمة المُعادة من MultiCell() هي دائماً 1»العَرَض. الشيفرة التي تتفرّع بناءً على القيمة المُعادة من MultiCell() (على سبيل المثال، لحساب الارتفاع المستخدَم أو عدد الأسطر) تتصرّف بطريقة غير صحيحة.
السبب. يُعيد MultiCell() في المهايئ القيمة النائبة للتوافق 1، لا عدد الخلايا أو عدد الأسطر المعروضة. وكذلك يُعيد Write() القيمة 0.
الإصلاح. لا تتفرّع بناءً على هذه القيم المُعادة. إذا احتجتَ إلى الارتفاع المعروض، فاحسبه من getStringHeight() / getNumLines()، أو انقُل ذلك المنطق إلى الواجهة البرمجية الحديثة.
setPDFVersion('1.4') لم يُنتِج ملف PDF 1.4
قسم بعنوان «setPDFVersion('1.4') لم يُنتِج ملف PDF 1.4»العَرَض. طلبتَ إصدار PDF أقدم؛ لكن الخرج ما زال PDF 2.0.
السبب. يُخرِج المهايئ دائماً PDF 2.0 (ISO 32000-2). setPDFVersion() يقع ضمن المجموعة غير المنطبقة؛ يُصدِر المهايئ إشعاراً ويتابع.
الإصلاح. أزِل الاستدعاء. إذا اشترط مستهلِك لاحق إصدار PDF أقدم، فعالِج ذلك الشرط على حِدة؛ فالمهايئ لا يستطيع استهداف إصدار أدنى.
setSignature() لم يفعل شيئاً — ملف PDF غير موقَّع
قسم بعنوان «setSignature() لم يفعل شيئاً — ملف PDF غير موقَّع»العَرَض. استدعيتَ setSignature() بشهادة؛ لكن ملف PDF الناتج لا يحمل توقيعاً.
السبب. لا ينفّذ المحرّك الأساسي setSignature() عبر هذا المهايئ. في الوضع الافتراضي يكون الاستدعاء عمليةً لاغية؛ وفي الوضع الصارم يرمي استثناءً.
الإصلاح. يتطلّب التوقيع إصداراً تجارياً من NextPDF والواجهة البرمجية الحديثة للتوقيع. راجِع /integrations/tcpdf-compat/security-and-operations/ § التوقيعات الرقمية. لا تتوقّع من استدعاء setSignature() القديم أن يوقِّع أي شيء.
Output() أفسد استجابة HTTP أو خرج العامل لديّ
قسم بعنوان «Output() أفسد استجابة HTTP أو خرج العامل لديّ»العَرَض. تظهر بايتات PDF في استجابة Hypertext Transfer Protocol (HTTP)، أو يتلوّث سجلّ عامل ببايتات PDF.
السبب. استخدمتَ وجهة خرج تكتب إلى مسار الخرج (I/D) بينما تتحكّم أنت في الاستجابة بنفسك. المهايئ لا يطبع داخل مخزِّنك المؤقّت كما يفعل TCPDF القديم، لكنّ I/D ما زالا يوجّهان خرج المحرّك.
الإصلاح. في العوامل والمعالِجات التي تتحكّم فيها، استخدِم Output($path, 'F') لكتابة ملف، أو Output($name, 'S') للحصول على البايتات وإصدارها بنفسك. يؤكِّد tests/Unit/Compat/Tcpdf/Bridge/OutputBridgeTest.php أن تخطيط الوجهة غير حسّاس لحالة الأحرف ومُقتطَع المسافات البيضاء:
| الرمز | القيمة المُعادة | الأثر الجانبي |
|---|---|---|
S | بايتات PDF (%PDF…) | لا شيء |
F | سلسلة فارغة | يكتب ملفاً |
E | متن MIME بترميز base64 | لا شيء |
FI / FD | سلسلة فارغة | يكتب ملفاً، ثم خرج المحرّك |
I / D / غير معروف | سلسلة فارغة | خرج المحرّك (مضمَّن/تنزيل) |
تأكيدات PDF على البايتات الدقيقة تفشل بعد التبديل
قسم بعنوان «تأكيدات PDF على البايتات الدقيقة تفشل بعد التبديل»العَرَض. تفشل اختبارات اللقطات التي تقارن بايتات PDF الخام في كل مكان.
السبب. يستخدم المحرّك تنفيذاً مستقلاً لـ PDF 2.0. تُنتِج الأساليب المُفوَّضة خرجاً مرئياً متوافقاً، لكنّ البايتات تختلف. هذا أمر متوقَّع.
الإصلاح. أعِد ضبط خطوط الأساس لاختباراتك بحيث تؤكّد المحتوى المعروض (النص المستخرَج)، أو البنية (عدد الصفحات، حجم الصفحة)، أو فحص تحقّق سريع (str_starts_with($bytes, '%PDF')). راجِع /integrations/tcpdf-compat/migration/ المرحلة 4.
ثابت K_* / PDF_* قديم له قيمة خاطئة
قسم بعنوان «ثابت K_* / PDF_* قديم له قيمة خاطئة»العَرَض. مسار مخصّص أو قيمة افتراضية ضبطتَها عبر ثابت لا يأخذ مفعوله.
السبب. لا يعرّف المهايئ ثابتاً تلقائياً إلا إذا لم يكن معرَّفاً مسبقاً، ويفعل ذلك أثناء أول إنشاء. إذا جرى define() لديك بعد إنشاء أول مهايئ، فإن قيمة المهايئ الافتراضية تكون قد أصبحت سارية بالفعل.
الإصلاح. عرِّف كل ثابت K_* / PDF_* مخصّص في طبقة التمهيد لديك، قبل إنشاء أي نسخة من المهايئ. راجِع /integrations/tcpdf-compat/configuration/ § ترتيب تحليل التهيئة.
عدم تطابق إصدار المحرّك عند الإنشاء
قسم بعنوان «عدم تطابق إصدار المحرّك عند الإنشاء»العَرَض. يفشل الإنشاء أو يتغيّر السلوك على نحو غير متوقَّع بعد تحديث تبعية.
السبب. يتطلّب المهايئ nextpdf/core ^3.0. أي إصدار أساسي يجري حله خارج هذا النطاق غير مدعوم.
الإصلاح. شغِّل composer show nextpdf/core، وثبِّت المحرّك على ^3.0. راجِع /integrations/tcpdf-compat/install/ § التحقّق من إصدار المحرّك.
مرجع تشخيصي سريع
قسم بعنوان «مرجع تشخيصي سريع»| السؤال | أين تبحث |
|---|---|
| ماذا يفعل الأسلوب X فعلياً هنا؟ | /integrations/tcpdf-compat/method-coverage/، docs/TCPDF_COVERAGE.md |
| أيٌّ من استدعاءاتي يفقد المُعامِلات؟ | تدقيق بالوضع الصارم (هذه الصفحة؛ /integrations/tcpdf-compat/migration/) |
| لماذا لم تتوقّف العملية عند الخطأ؟ | /integrations/tcpdf-compat/security-and-operations/ § السلوكيات المُحصَّنة |
| لماذا الخرج غير موقَّع / ليس PDF/A؟ | /integrations/tcpdf-compat/security-and-operations/ |
| تعارض الاسم البديل مقابل الاستيراد الصريح | هذه الصفحة؛ /integrations/tcpdf-compat/boot-and-discovery/ |
انظر أيضاً
قسم بعنوان «انظر أيضاً»- /integrations/tcpdf-compat/migration/ — الترحيل المرحلي الذي يمنع معظم ما سبق
- /integrations/tcpdf-compat/method-coverage/ — مرجع سلوك كل أسلوب
- /integrations/tcpdf-compat/boot-and-discovery/ — تسجيل الأسماء البديلة وتجنّب التعارض
docs/TCPDF_COVERAGE.md— مصفوفة التغطية المعتمَدة