ابنِ استراتيجية أخطاء كاملة: استثناءات عمل متسلسلة، وfinally منضبط، ومعالِجات شاملة كخط دفاع أخير.
افتح هذا الدرس في Kodokonمنذ PHP 7، كل ما يُطلَق ينفّذ Throwable، بفرعين: Error (إخفاقات المحرّك والأنواع، مثل TypeError) وException (إخفاقات التطبيق). ولا تلتقط Error إلا عند حدود البرنامج. أما على صعيد التطبيق، فتوفّر مكتبة SPL تسلسلًا هرميًا جاهزًا: يشير LogicException إلى خلل من المطوّر، يجب إصلاحه؛ ويشير RuntimeException إلى طارئ وقت التشغيل، يجب معالجته. ورد الفعل المهني: اشتقّ استثناءات العمل لديك من هذه القواعد، استثناءً واحدًا لكل حالة يمكن تحديدها.
<?php
declare(strict_types=1);
abstract class AppException extends RuntimeException
{
}
final class UserNotFound extends AppException
{
public static function withEmail(
string $email
): self {
return new self("No user for $email");
}
}
try {
throw UserNotFound::withEmail('lea@example.com');
} catch (UserNotFound $e) {
echo $e->getMessage();
}لا قيمة لـ try/catch إلا إذا كنت تعرف ما تفعله بالخطأ - وإلا، فدعه يصعد إلى الأعلى. وثلاث أدوات تصقل التحكّم: الالتقاط المتعدّد catch (JsonException | ValueError $e) يجمع المعالجة المتطابقة؛ ويربط الوسيط previous السبب الأصلي بسلسلة عندما تترجم استثناءً تقنيًا إلى استثناء عمل؛ وتُنفَّذ finally في كل الأحوال - النجاح، والاستثناء، وحتى return مبكر - وهي مثالية لتحرير مورد.
<?php
declare(strict_types=1);
final class PayloadInvalid extends RuntimeException
{
}
function decode(string $json): mixed
{
try {
return json_decode(
$json,
true,
flags: JSON_THROW_ON_ERROR,
);
} catch (JsonException $e) {
throw new PayloadInvalid(
'Invalid JSON payload',
previous: $e,
);
} finally {
echo "decode() finished\n";
}
}
try {
decode('{broken');
} catch (PayloadInvalid $e) {
echo $e->getPrevious()?->getMessage();
}في نهاية السلسلة، يُغلق معالِجان شاملان الإعداد. يلتقط set_exception_handler كل ما لم يُعالَج: تسجيل مُنظَّم، واستجابة 500 عامة - دون كشف الرسالة أو التتبّع (trace) للمستخدم أبدًا. ويحوّل set_error_handler الأخطاء القديمة (التحذيرات، والإشعارات) إلى ErrorException، موحِّدًا العالَمين: فيصبح كل شيء استثناءً، ويتّبع كل شيء مسار المعالجة نفسه.
<?php
declare(strict_types=1);
set_error_handler(function (
int $severity,
string $message,
string $file,
int $line,
): bool {
throw new ErrorException(
$message,
0,
$severity,
$file,
$line,
);
});
set_exception_handler(function (Throwable $e): void {
error_log($e->getMessage());
http_response_code(500);
echo 'A technical error occurred.';
});
trigger_error('Legacy warning', E_USER_WARNING);
echo 'Never reached';Error وException في PHP الحديثة؟Error من ExceptionThrowablefinally؟previous في الاستثناء؟