Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تسلسل الاستثناءات المخصصة

جزء من قسم البرمجة كائنية التوجه في رحلة 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;
    }
}

تجعل بنية الاستثناءات المصممة جيدًا شيفرتك أسهل في الصيانة. عند التقاط الاستثناءات، يمكنك أن تكون عامًا أو محددًا بالقدر اللازم، كما تحمل كائنات الاستثناء نفسها سياقًا ذا معنى حول ما حدث من خطأ.

challenge icon

التحدي

سهل

لننشئ نظامًا لمعالجة الطلبات باستخدام تسلسل هرمي مخصص للاستثناءات، يتعامل مع أنواع مختلفة من حالات فشل الطلبات. ستنشئ استثناءات تحمل سياقًا ذا معنى حول ما حدث من خطأ، مما يجعل معالجة الأخطاء أكثر دقة ووضوحًا.

ستنظم التعليمات البرمجية عبر أربعة ملفات:

  • 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() الخاصة به.

يتيح لك هذا التسلسل الهرمي التعامل مع الاستثناءات المحددة بشكل فردي، مع الاحتفاظ بإمكانية التقاط جميع المشكلات المرتبطة بالطلبات من خلال الفئة الأساسية 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()

?>
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم PHP عبر الإنترنت