تسلسل الاستثناءات المخصصة
جزء من قسم البرمجة كائنية التوجه في رحلة PHP على Coddy. الدرس 67 من 91.
بينما تغطي فئات exception المضمّنة في PHP السيناريوهات الشائعة، غالبًا ما تحتاج التطبيقات الفعلية إلى أنواع أكثر تحديدًا من الأخطاء. يتيح لك إنشاء هرمية exceptions مخصّصة تعريف exceptions تتوافق مع مجالك والتقاطها باستخدام catch بمستويات مختلفة من التحديد.
لإنشاء استثناء مخصص، ما عليك سوى توسيع الفئة Exception أو إحدى فئاتها الفرعية:
<?php
class PaymentException extends Exception {}
class InsufficientFundsException extends PaymentException {
public function __construct(
private float $required,
private float $available
) {
parent::__construct("Need $required but only $available available");
}
public function getShortfall(): float {
return $this->required - $this->available;
}
}
لاحظ أن InsufficientFundsException ترث من PaymentException، وليس من Exception مباشرةً. ينشئ هذا تسلسلاً هرميًا يتيح لك التقاط جميع الاستثناءات المتعلقة بالدفع باستخدام كتلة catch واحدة، أو معالجة استثناءات محددة كلٌّ على حدة.
يمكن أن تتضمن الاستثناءات المخصّصة خصائص وأساليب إضافية ذات صلة بالخطأ. هنا، توفّر getShortfall() معلومات مفيدة لا يمكن لاستثناء عام تقديمها:
<?php
class Wallet {
public function __construct(private float $balance) {}
public function pay(float $amount): void {
if ($amount > $this->balance) {
throw new InsufficientFundsException($amount, $this->balance);
}
$this->balance -= $amount;
}
}
تجعل بنية الاستثناءات المصممة جيدًا شيفرتك أسهل في الصيانة. عند التقاط الاستثناءات، يمكنك أن تكون عامًا أو محددًا بالقدر اللازم، كما تحمل كائنات الاستثناء نفسها سياقًا ذا معنى حول ما حدث من خطأ.
التحدي
سهللننشئ نظامًا لمعالجة الطلبات باستخدام تسلسل هرمي مخصص للاستثناءات، يتعامل مع أنواع مختلفة من حالات فشل الطلبات. ستنشئ استثناءات تحمل سياقًا ذا معنى حول ما حدث من خطأ، مما يجعل معالجة الأخطاء أكثر دقة ووضوحًا.
ستنظم التعليمات البرمجية عبر أربعة ملفات:
OrderException.php: أنشئ فئة أساسية باسمOrderExceptionتمتد منException. تعمل هذه الفئة كأصل لجميع الاستثناءات المرتبطة بالطلبات، مما يتيح لك التقاط أي مشكلة في الطلب باستخدام كتلةcatchواحدة عند الحاجة.OutOfStockException.php: أنشئ فئة باسمOutOfStockExceptionتمتد منOrderException. يجب أن يقبل هذا الاستثناء اسم المنتج والكمية المطلوبة في الباني الخاص به. استخدم ترقية خصائص الباني لهذه الخصائص الخاصة. استدعِ باني الفئة الأصل باستخدام رسالة بالتنسيق"[productName] is out of stock (requested: [quantity])". أضف دالة باسمgetProductName(): stringتُرجع اسم المنتج.InvalidQuantityException.php: أنشئ فئة باسمInvalidQuantityExceptionتمتد منOrderException. يجب أن يقبل هذا الاستثناء قيمة الكمية في الباني الخاص به باستخدام ترقية الباني كخاصية خاصة. استدعِ باني الفئة الأصل باستخدام الرسالة"Invalid quantity: [quantity]". أضف دالة باسمgetQuantity(): intتُرجع قيمة الكمية.main.php: ضمّن ملفات الاستثناءات الثلاثة جميعها. ستتلقى مدخلين: اسم منتج وكمية (كسلسلة نصية تحتاج إلى تحويلها إلى عدد صحيح).بناءً على قيمة الكمية، اطرح الاستثناء المناسب:
- إذا كانت الكمية أقل من 1، فاطرح استثناء
InvalidQuantityException - إذا كانت الكمية أكبر من 100، فاطرح استثناء
OutOfStockException(لمحاكاة عدم كفاية المخزون) - خلاف ذلك، اطبع
"Order placed: [quantity]x [productName]"
التقط الاستثناءات باستخدام التسلسل الهرمي. التقط أولًا
InvalidQuantityExceptionواطبع"Quantity error: [message] (value: [quantity])"باستخدام رسالة الاستثناء ودالةgetQuantity()الخاصة به. ثم التقطOutOfStockExceptionواطبع"Stock error: [message] (product: [productName])"باستخدام رسالة الاستثناء ودالةgetProductName()الخاصة به.- إذا كانت الكمية أقل من 1، فاطرح استثناء
يتيح لك هذا التسلسل الهرمي التعامل مع الاستثناءات المحددة بشكل فردي، مع الاحتفاظ بإمكانية التقاط جميع المشكلات المرتبطة بالطلبات من خلال الفئة الأساسية OrderException. وتوفر الدوال المخصصة في كل استثناء سياقًا لا يمكن لاستثناء عام توفيره.
جرّب بنفسك
<?php
// تضمين جميع ملفات الاستثناءات
require_once 'OrderException.php';
require_once 'OutOfStockException.php';
require_once 'InvalidQuantityException.php';
// قراءة الإدخال
$productName = trim(fgets(STDIN));
$quantity = intval(trim(fgets(STDIN)));
// TODO: استخدم try-catch للتعامل مع معالجة الطلب
// داخل كتلة try:
// - إذا كان quantity < 1، throw InvalidQuantityException
// - إذا كان quantity > 100، throw OutOfStockException
// - وإلا، اطبع "Order placed: [quantity]x [productName]"
//
// Catch InvalidQuantityException أولاً:
// - اطبع "Quantity error: [message] (value: [quantity])" باستخدام getMessage() و getQuantity()
//
// Catch OutOfStockException:
// - اطبع "Stock error: [message] (product: [productName])" باستخدام getMessage() و getProductName()
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsالكلمة المفتاحية $thisالـ Methodsالـ Propertiesالمنشئ (__construct)الهادم (__destruct)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةالكلمة المفتاحية parent::إعادة تعريف الدوال (Method Overriding)الكلمة المفتاحية finalالأصناف المجردة (Abstract Classes)مراجعة - هيكلية الموظفين7التغليف (Encapsulation)
العام، المحمي، الخاص (Public, Protected, Private)نظرة متعمقة على معدلات الوصولدوال Getters و Settersإخفاء المعلوماتميزة Constructor Promotion (8.0)مراجعة - نظام سجلات الطلاب10مفاهيم البرمجة كائنية التوجه المتقدمة
التركيب مقابل الوراثةحقن التبعيةالأصناف المجهولةالتعدادات (PHP 8.1)الألياف (PHP 8.1)تعمق في استنساخ الكائناتالمولدات والمكررات13أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع2مساحات الأسماء والتحميل التلقائي
مقدمة إلى مساحات الأسماءالكلمة المفتاحية useمعيار التحميل التلقائي PSR-4أداة التحميل التلقائي Composerملخص - مشروع منظم5الواجهات والعقود
مقدمة إلى الواجهاتتنفيذ الواجهاتتنفيذ واجهات متعددةالواجهة مقابل الـ Abstract Classالـ Type Hinting مع الواجهاتملخص - حاسبة الأشكال8الميثودات السحرية (Magic Methods)
مقدمة في الميثودات السحرية__toString و __debugInfo__get, __set, __isset, __unset__call و __callStatic__clone واستنساخ الكائنات__serialize و __unserializeمراجعة - Custom Collection11نظام الأنواع ومعالجة الأخطاء
تصريحات الأنواعالأنواع القابلة للقيمة Nullأنواع الاتحاد والتقاطعفئات الاستثناءاتتسلسل الاستثناءات المخصصةTry, Catch, Finallyمراجعة - مدقق النماذج3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)تدرّب بنفسك: مترجم PHP عبر الإنترنت