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

التعدادات (PHP 8.1)

جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 59 من 91.

قبل PHP 8.1، كان تمثيل مجموعة ثابتة من القيم مثل الحالات أو الأنواع يعني استخدام ثوابت الفئات (class constants) أو السلاسل النصية السحرية (magic strings) - وكلاهما أساليب عرضة للأخطاء. توفر Enums (التعدادات) طريقة صحيحة لتعريف نوع يمكنه فقط الاحتفاظ بقيم محددة مسبقاً.

قم بتعريف enum باستخدام الكلمة المفتاحية enum:

<?php
enum Status {
    case Pending;
    case Active;
    case Completed;
}

$status = Status::Active;
echo $status->name;

المخرجات:

Active

يمكن للتعدادات (Enums) أن تحتوي أيضاً على قيم مدعومة (backed values) - وهي قيم نصية أو صحيحة مرتبطة بكل حالة. هذا مفيد عند تخزين التعدادات في قواعد البيانات أو واجهات برمجة التطبيقات (APIs):

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value;

المخرجات:

active

توفر التعدادات المدعومة (Backed enums) دالة from() لإنشاء تعداد من قيمته، ودالة tryFrom() التي تعيد null بدلاً من رمي خطأ للقيم غير الصالحة:

<?php
$status = Status::from('active');      // يعيد Status::Active
$invalid = Status::tryFrom('unknown'); // يعيد null

يمكن أن تحتوي التعدادات (Enums) أيضاً على أساليب (methods)، مما يجعلها قوية لتغليف المنطق المرتبط بها. وهي تعمل بسلاسة مع تلميحات النوع (type hints)، مما يضمن أن دوالك لا تقبل إلا القيم الصالحة - فلا داعي بعد الآن للتحقق مما إذا كانت السلسلة النصية (string) تطابق الخيارات المتوقعة.

challenge icon

التحدي

سهل

لنقم ببناء نظام لإدارة الطلبات يستخدم التعدادات (enums) لتمثيل حالات الطلب بطريقة آمنة من حيث النوع (type-safe). بدلاً من الاعتماد على السلاسل النصية التي قد تُكتب بشكل خاطئ أو تكون غير صالحة، ستقوم بإنشاء تعداد مدعوم (backed enum) يربط كل حالة بقيمة مناسبة لقاعدة البيانات.

ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:

  • OrderStatus.php — أنشئ تعداداً مدعوماً بسلسلة نصية يسمى OrderStatus مع أربع حالات:
    • Pending مدعومة بـ 'pending'
    • Processing مدعومة بـ 'processing'
    • Shipped مدعومة بـ 'shipped'
    • Delivered مدعومة بـ 'delivered'
    أضف دالة label() تُرجع وصفاً قابلاً للقراءة لكل حالة:
    • Pending تُرجع "Awaiting confirmation"
    • Processing تُرجع "Being prepared"
    • Shipped تُرجع "On the way"
    • Delivered تُرجع "Order complete"
  • Order.php — أنشئ فئة Order تستخدم التعداد. قم بتضمين ملف OrderStatus. يجب أن تقوم الفئة بما يلي:
    • قبول معرف الطلب (string) و OrderStatus في منشئ الفئة (constructor) باستخدام خاصية constructor promotion
    • امتلاك دالة getInfo() تُرجع "Order [id]: [status label]"
    • امتلاك دالة getStatusValue() تُرجع القيمة المدعومة للحالة (مفيدة لتخزين قاعدة البيانات)
  • main.php — قم بتضمين ملف Order. ستتلقى مدخلين: معرف الطلب وسلسلة نصية للحالة (مثل "shipped"). استخدم tryFrom() لتحويل السلسلة النصية المدخلة بأمان إلى تعداد OrderStatus. إذا كانت الحالة صالحة، فقم بإنشاء Order واطبع سطرين:
    • نتيجة getInfo()
    • نتيجة getStatusValue()
    إذا كانت سلسلة الحالة غير صالحة، اطبع "Invalid status".

يوضح هذا التحدي كيف توفر التعدادات أماناً للنوع — حيث لا يمكن لفئة Order الخاصة بك إلا قبول حالات صالحة، وتسمح لك دالة tryFrom() بالتعامل بأمان مع مدخلات المستخدم دون المخاطرة بقيم غير صالحة.

ورقة مرجعية

توفر التعدادات (Enums) طريقة آمنة من حيث النوع لتعريف مجموعة ثابتة من القيم. قم بتعريف التعداد باستخدام الكلمة المفتاحية enum:

<?php
enum Status {
    case Pending;
    case Active;
    case Completed;
}

$status = Status::Active;
echo $status->name; // المخرجات: Active

تربط التعدادات المدعومة (Backed enums) قيمًا نصية أو صحيحة بكل حالة:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value; // المخرجات: active

استخدم from() لإنشاء تعداد من قيمته، أو tryFrom() التي تعيد null للقيم غير الصالحة:

<?php
$status = Status::from('active');      // تعيد Status::Active
$invalid = Status::tryFrom('unknown'); // تعيد null

يمكن أن تحتوي التعدادات على دوال (methods) لتغليف المنطق البرمجي المرتبط بها:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    
    public function label(): string {
        return match($this) {
            self::Pending => 'Awaiting',
            self::Active => 'In Progress',
        };
    }
}

جرّب بنفسك

<?php

require_once 'Order.php';

// قراءة المدخلات
$orderId = trim(fgets(STDIN));
$statusString = trim(fgets(STDIN));

// TODO: استخدم OrderStatus::tryFrom() لتحويل سلسلة الحالة بأمان إلى enum
// تعيد tryFrom() القيمة null إذا كانت القيمة غير صالحة

// TODO: إذا كانت الحالة صالحة، قم بإنشاء Order واطبع:
// - نتيجة getInfo()
// - نتيجة getStatusValue()

// TODO: إذا كانت الحالة غير صالحة، اطبع "Invalid status"

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

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

جميع دروس Object Oriented Programming