معالجة الأخطاء في PHP: من try/catch إلى الحلول الصناعية
\n\nكل مطور PHP يواجه أخطاء. try/catch الأساسي هو مجرد قمة جبل الجليد. في هذه المقالة، سنستعرض التقنيات المتقدمة لمعالجة الأخطاء التي تحول الكود الهش إلى نظام موثوق قادر على الاستجابة بشكل صحيح لأي أعطال.
1. الغوص العميق في try/catch: كتلة finally و catch المتعددة
\n\ntry/catch القياسي هو الأساس، لكن الكثيرين ينسون كتلة finally التي يتم تنفيذها دائمًا، بغض النظر عن وجود استثناء. هذا هو المكان المثالي لإغلاق الموارد (الملفات، اتصالات قاعدة البيانات).
<?php\nfunction processFile(string $filename): void {\n $handle = fopen($filename, 'r');\n if (!$handle) {\n throw new \\RuntimeException("فشل فتح الملف: $filename");\n }\n \n try {\n // معالجة الملف\n while (($line = fgets($handle)) !== false) {\n // ... منطق المعالجة\n }\n } catch (\\RuntimeException $e) {\n // معالجة محددة لأخطاء الإدخال/الإخراج\n error_log("خطأ في قراءة الملف: " . $e->getMessage());\n throw $e; // إعادة الرمي للأعلى\n } catch (\\Exception $e) {\n // معالجة أي استثناءات أخرى\n error_log("خطأ غير معروف: " . $e->getMessage());\n throw $e;\n } finally {\n fclose($handle); // دائمًا نغلق الملف\n }\n}\n?>\n\nهام: ترتيب كتل catch له أهمية. الاستثناءات الأكثر تحديدًا (مثل \\RuntimeException) يجب أن تأتي قبل العامة (\\Exception). وإلا فلن يتم تنفيذ الكتلة المحددة أبدًا.
2. فئات الاستثناءات المخصصة: الدلالات والتسلسل الهرمي
\n\nالاستثناءات المضمنة (PDOException, RuntimeException) غالبًا ما تكون غير كافية من حيث المعلومات. أنشئ تسلسلك الهرمي الخاص للاستثناءات لفصل الأخطاء حسب الأنواع وتبسيط معالجتها.
\n\n<?php\n// الاستثناء الأساسي للتطبيق\nclass AppException extends \\Exception {}\n\n// أخطاء التحقق\nclass ValidationException extends AppException {\n private array $errors;\n \n public function __construct(array $errors, string $message = "خطأ في التحقق") {\n parent::__construct($message, 422);\n $this->errors = $errors;\n }\n \n public function getErrors(): array {\n return $this->errors;\n }\n}\n\n// أخطاء الوصول\nclass AccessDeniedException extends AppException {\n public function __construct(string $message = "الوصول ممنوع") {\n parent::__construct($message, 403);\n }\n}\n\n// مثال على الاستخدام\nfunction registerUser(array $data): void {\n $errors = [];\n \n if (empty($data['email'])) {\n $errors['email'] = 'البريد الإلكتروني مطلوب';\n }\n if (empty($data['password'])) {\n $errors['password'] = 'كلمة المرور مطلوبة';\n }\n \n if (!empty($errors)) {\n throw new ValidationException($errors);\n }\n \n // منطق التسجيل...\n}\n\ntry {\n registerUser(['email' => '']);\n} catch (ValidationException $e) {\n // معالجة محددة: إرجاع JSON مع الأخطاء\n http_response_code(422);\n echo json_encode(['errors' => $e->getErrors()]);\n} catch (AccessDeniedException $e) {\n http_response_code(403);\n echo json_encode(['error' => $e->getMessage()]);\n} catch (AppException $e) {\n // معالجة عامة لجميع أخطاء التطبيق الأخرى\n http_response_code(500);\n echo json_encode(['error' => 'خطأ داخلي في الخادم']);\n}\n?>\n\nنصيحة: استخدم رموز HTTP (400, 403, 422, 500) كرموز للاستثناءات - فهذا يبسط التكامل مع REST API.
\n\n3. معالج الأخطاء الشامل: ErrorHandler و ShutdownHandler
\n\nلا يمكن التقاط جميع الأخطاء عبر try/catch. الأخطاء الفادحة (E_ERROR)، التحذيرات (E_WARNING)، وأخطاء التحليل