معالجة الأخطاء في PHP: try/catch وما بعده
معالجة الأخطاء هي إحدى المهام الأساسية لأي مطور ويب. الكود المكتوب بشكل جيد في PHP لا ينفذ منطق الأعمال فحسب، بل يتفاعل بشكل صحيح مع المواقف غير المتوقعة: فقدان ملف، مشاكل في قاعدة البيانات، إدخال بيانات غير صحيح من المستخدم. في هذه المقالة، سنشرح بالتفصيل كيفية عمل معالجة الأخطاء في PHP، بدءًا من الأساسيات try/catch وصولاً إلى التقنيات المتقدمة — الاستثناءات المخصصة والمعالجات العامة.
1. الأساسيات: بنية try/catch
الطريقة الأكثر شيوعًا لمعالجة الأخطاء في PHP الحديثة هي بنية try/catch. تسمح هذه البنية بـ"التقاط" الاستثناء (كائن من الفئة Throwable أو ورثتها) وتنفيذ كود بديل بدلاً من إنهاء السكريبت بشكل طارئ.
الصيغة الأساسية تبدو كالتالي:
<?phptry { // كود قد يرمي استثناء $file = fopen('data.txt', 'r'); if (!$file) { throw new Exception('تعذر فتح الملف'); } // العمل مع الملف...} catch (Exception $e) { // معالجة الخطأ echo 'حدث خطأ: ' . $e->getMessage();}?>في كتلة try يتم وضع الكود الذي قد يكون خطيرًا. إذا حدث استثناء داخله (عبر throw أو بسبب خطأ داخلي في PHP)، ينتقل التنفيذ فورًا إلى كتلة catch. المتغير $e يحتوي على كائن الاستثناء، ويمكن استدعاء دوال منه:
getMessage()— نص الخطأ;getCode()— رمز الخطأ الرقمي;getFile()— الملف الذي حدث فيه الخطأ;getLine()— السطر الذي تسبب في الخطأ.
2. كتلة finally: كود يتم تنفيذه دائمًا
أحيانًا يكون من الضروري تنفيذ إجراءات معينة بغض النظر عما إذا حدث خطأ أم لا — مثل إغلاق اتصال قاعدة البيانات أو تحرير الموارد. لهذا الغرض تُستخدم كتلة finally:
<?phpfunction processData($data) { try { // عملية خطيرة if (empty($data)) { throw new InvalidArgumentException('البيانات لا يمكن أن تكون فارغة'); } echo "معالجة البيانات..."; return true; } catch (InvalidArgumentException $e) { echo "خطأ: " . $e->getMessage() . ""; return false; } finally { echo "كتلة finally يتم تنفيذها دائمًا."; }}
processData([]); // سيظهر: خطأ: البيانات لا يمكن أن تكون فارغة، ثم كتلة finallyprocessData('test'); // سيظهر: معالجة البيانات...، ثم كتلة finally?>كتلة finally يتم تنفيذها حتى إذا كان هناك أمر return في try أو catch. هذا يضمن تحرير الموارد.
3. الاستثناءات المخصصة: توسيع الفئة Exception
في المشاريع الحقيقية، نادرًا ما يتم الاكتفاء بالفئة القياسية Exception. من الأسهل بكثير إنشاء فئات استثناء خاصة لأنواع مختلفة من الأخطاء. هذا يجعل الكود أكثر قابلية للقراءة ويبسط التقاط الحالات المحددة.
مثال: لننشئ استثناءً لأخطاء التحقق واستثناءً لأخطاء قاعدة البيانات.
<?phpclass ValidationException extends Exception {}class DatabaseException extends Exception {}
function validateUser($age) { if ($age < 0 || $age > 150) { throw new ValidationException('عمر غير صحيح'); } return true;}
function connectToDatabase($dsn) { if (empty($dsn)) { throw new DatabaseException('DSN لا يمكن أن يكون فارغًا'); } // محاكاة الاتصال...}
try { validateUser(200);} catch (ValidationException $e) { echo 'خطأ تحقق: ' . $e->getMessage();}
try { connectToDatabase('');} catch (DatabaseException $e) {