انتقل إلى محتوى الدرس
الدرس 73
دورة PHP

التعدادات Enums والأصناف للقراءة فقط وخطافات الخصائص في PHP 8.4PHP Enums Readonly Classes and Property Hooks

ابنِ نماذج بيانات قوية في PHP 8.4 باستخدام التعدادات Enums والأصناف للقراءة فقط readonly وخطافات الخصائص الحديثة.
أقسام الدرس
6
الأمثلة
6
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
0
محتوى الدرس
في هذا الدرس 6تصفّح المواضيع

تُعرّف التعدادات (enum) المضافة في PHP 8.1 نوع بيانات مغلقاً وصارماً يقتصر على مجموعة محددة من الحالات المسماة (case)، بدلاً من النصوص العشوائية القابلة للخطأ الإملائي.

  • عرّف الحالات المسموحة داخل enum باستخدام الكلمة المفتاحية case (مثل case Pending;).
  • كل حالة داخل التعداد تمثل كائناً وحيداً (Singleton) من نوع هذا التعداد، لذا تقارن الحالات بالمطابقة الصارمة ===.
  • تمتلك كل حالة تلقائياً خاصية للقراءة فقط باسم $case->name تحتوي على الاسم النصي للحالة.

تحدد الدالة assignSla() نوع المعامل كـ TicketPriority، مما يجعل تمرير أي قيمة غير صالحة مستحيلاً.

مخطط توضيحي: محاكي التعدادات Enums والأصناف للقراءة فقط وخطافات الخصائص في PHP 8.4
PHP
<?php
enum TicketPriority {
    case Low;
    case Medium;
    case Critical;
}
function assignSla(TicketPriority $p): string {
    return $p === TicketPriority::Critical ? "1 Hour SLA" : "24 Hour SLA";
}
$current = TicketPriority::Critical;
echo $current->name . " -> " . assignSla($current) . "\n";

عندما تحتاج لتخزين التعداد في قاعدة البيانات أو إرساله عبر النماذج وملفات JSON، عرّف تعداداً مدعوماً بقيم قياسية (Backed Enum) من النوع string أو int.

  • حدد نوع القيمة المدعومة بعد نقطتين رأسيتين (enum OrderStatus: string) وأسند قيمة فريدة لكل حالة.
  • اقرأ القيمة النصية أو الرقمية للحالة عبر الخاصية المدمجة $case->value.
  • حوّل مدخلات المستخدم أو قاعدة البيانات بأمان إلى حالة تعداد عبر الدالة OrderStatus::tryFrom($raw) التي تُرجع null عند عدم التطابق.

تُرجع tryFrom("shipped") الحالة OrderStatus::Shipped، بينما تُرجع tryFrom("unknown_state") القيمة null بأمان تام.

PHP
<?php
enum OrderStatus: string {
    case Pending = "pending";
    case Shipped = "shipped";
    case Cancelled = "cancelled";
}
$valid = OrderStatus::tryFrom("shipped");
$invalid = OrderStatus::tryFrom("unknown_state");

echo "Valid   : " . ($valid?->name ?? "NULL") . " ({$valid?->value})\n";
echo "Invalid : " . ($invalid?->name ?? "NULL (Safe Fallback)") . "\n";

التعدادات في PHP كائنات غنية المزايا؛ فيمكنها تطبيق الواجهات (implements)، وتعريف الدوال التي تستخدم $this وتعبير match($this).

  • داخل دالة التعداد، تشير الكلمة $this إلى حالة التعداد المحددة التي تم استدعاء الدالة عليها.
  • دمج دوال التعداد مع تعبير match($this) يجمع العناوين والألوان والصلاحيات في مكان واحد منظم.
  • لا يمكن للتعدادات احتواء خصائص متغيرة ولا يمكنها الوراثة عبر extends.

يطبق التعداد Role الواجهة HasBadge ويربط كل حالة بلون الشارة المقابل عبر تعبير match($this).

PHP
<?php
interface HasBadge { public function badgeColor(): string; }
enum Role: string implements HasBadge {
    case Admin = "admin";
    case Viewer = "viewer";
    public function badgeColor(): string {
        return match ($this) {
            self::Admin => "purple",
            self::Viewer => "slate",
        };
    }
}
echo Role::Admin->value . " badge=" . Role::Admin->badgeColor() . "\n";

إن وسم الخاصية بـ readonly (في PHP 8.1) أو وسم الصنف بالكامل كـ readonly class (في PHP 8.2+) يضمن إسناد قيم الخصائص مرة واحدة فقط ومنع تعديلها لاحقاً.

  • كتابة readonly class TransferRequest تجعل كل خاصية معلنة داخل الصنف للقراءة فقط (readonly) تلقائياً.
  • يجب إلزاماً تحديد نوع البيانات لكل خاصية داخل الصنف readonly (ويمكن استخدام mixed عند تعدد الأنواع).
  • دمج readonly class مع ترقية خصائص الباني ينشئ كائنات نقل بيانات غير قابلة للتعديل (DTOs) في بضعة أسطر نظيفة.

بمجرد إنشاء الكائن $dto، يمنع محرك PHP أي محاولة لتغيير قيم خصائصه مثل $dto->amountCents = 0; في أي مكان بالكود.

مخطط تدفق التنفيذ العملي لقسم بناء كائنات ثابتة بالأصناف readonly في لغة PHP
PHP
<?php
readonly class PaymentDto {
    public function __construct(
        public string $txId,
        public int $amountCents,
        public string $currency = "SAR"
    ) {}
}
$dto = new PaymentDto("TX-900", 25000);
echo "{$dto->txId}: {$dto->amountCents} {$dto->currency}\n";

يقدّم PHP 8.4 خطافات الخصائص الأصلية (get وset) والرؤية غير المتماثلة (public private(set)) للاستغناء عن دوال القراءة والتعديل التقليدية المكررة.

  • أرفق خطاف set مباشرة بالخاصية (مثل public string $email { set => strtolower(trim($value)); }) لتنقية القيمة تلقائياً عند كل إسناد.
  • أنشئ خاصية افتراضية محسوبة باستخدام خطاف get فقط دون حجز مساحة تخزين إضافية في الكائن.
  • استخدم الرؤية غير المتماثلة public private(set) int $points = 0; لكي يُسمح بقراءة الخاصية من الخارج مع حصر تعديلها داخل الصنف نفسه فقط.

إسناد $p->name يشغل خطاف set في PHP 8.4 تلقائياً لتهذيب الاسم، بينما تُقرأ $loyaltyPoints علناً ولا تُعدل إلا عبر دوال الصنف.

PHP
<?php
class CustomerProfile {
    public string $name {
        set => ucwords(strtolower(trim($value)));
    }
    public private(set) int $loyaltyPoints = 100;
    public function addPoints(int $pts): void { $this->loyaltyPoints += $pts; }
}
$p = new CustomerProfile();
$p->name = "  tariq al-ali  ";
$p->addPoints(50);
echo "{$p->name} | Points: {$p->loyaltyPoints}\n";

اجمع بين التعدادات (Enums) والأصناف للقراءة فقط (Readonly) وخطافات الخصائص والرؤية غير المتماثلة لبناء نماذج بيانات حديثة ومحمية ذاتياً في PHP 8.4.

  • استخدم التعدادات المدعومة (Backed Enums) لتمثيل الحالات المحدودة كالأدوار والعملات وحالات الطلبات.
  • استخدم readonly class لكائنات القيم الثابتة وطلبات API وبيانات الأحداث التي لا تتغير بعد إنشائها.
  • استخدم خطافات الخصائص وpublic private(set) في PHP 8.4 للكيانات القابلة للتحديث المنضبط عبر دوال الصنف.

يجمع الصنف SubscriptionSnapshot بين readonly class والتعداد المدعوم PlanTier لضمان سلامة النوع والحالة معاً.

الميزة البرمجيةإصدار PHPحالة الاستخدام الأساسية
Pure & Backed enumPHP 8.1+Fixed set of states, roles, or types (tryFrom)
readonly propertiesPHP 8.1+Write-once immutable object properties
readonly classPHP 8.2+Full immutable DTOs and Value Objects
Property Hooks (get / set)PHP 8.4+Inline normalization and computed properties
Asymmetric Visibility (public private(set))PHP 8.4+Public read access with private/protected mutation

PHP
<?php
enum PlanTier: string { case Free = "free"; case Pro = "pro"; }
readonly class SubscriptionSnapshot {
    public function __construct(public string $account, public PlanTier $tier) {}
}
$sub = new SubscriptionSnapshot("acc_402", PlanTier::from("pro"));
echo "{$sub->account} is on {$sub->tier->name} ({$sub->tier->value})\n";
خلاصة المعرفة ومحطة الانتقال

ملخص الدرس

حصاد الدرس

مراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي

ماذا تعلّمت في هذا الدرس؟

اجمع بين التعدادات (Enums) والأصناف للقراءة فقط (Readonly) وخطافات الخصائص والرؤية غير المتماثلة لبناء نماذج بيانات حديثة ومحمية ذاتياً في PHP 8.4. استخدم التعدادات المدعومة (Backed Enums) لتمثيل الحالات المحدودة كالأدوار والعملات وحالات الطلبات. استخدم readonly class لكائنات القيم الثابتة وطلبات API وبيانات الأحداث التي لا تتغير بعد إنشائها. استخدم خطافات الخصائص وpublic private(set) في PHP 8.4 للكيانات القابلة للتحديث المنضبط عبر دوال الصنف.

مشاركة

هل كان هذا الدرس مفيدًا؟

جارٍ تحميل الآراء…

ابنِ لغتك البرمجية

المصطلحات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 Enums & Readonly Enums و Readonly
ابنِ نماذج بيانات قوية في PHP 8.4 باستخدام التعدادات Enums والأصناف للقراءة فقط readonly وخطافات الخصائص الحديثة.
للمراجعة
02 Declaring Pure Enums in PHP 8 تعريف التعدادات الصرفة Pure Enums
المفهوم الأساسي لقسم تعريف التعدادات الصرفة Pure Enums في لغة PHP الحديثة.
للمراجعة
03 Backed Enums with from and tryFrom التعدادات المدعومة بقيم ودالتا from و tryFrom
الصياغة البرمجية والتطبيق العملي المباشر لقسم التعدادات المدعومة بقيم ودالتا from و tryFrom.
للمراجعة
04 Adding Methods and Interfaces to Enums إضافة الدوال والواجهات داخل Enums
قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم إضافة الدوال والواجهات داخل Enums.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 PHP PHP
PHP: Hypertext Preprocessor
لغة البرمجة النصية على جانب الخادم لبناء تطبيقات الويب الديناميكية وواجهات البرمجة.
للمراجعة
02 CLI CLI
Command-Line Interface
واجهة سطر الأوامر التي تتيح تشغيل ملفات PHP مباشرة عبر الطرفية.
للمراجعة
03 FPM FPM
FastCGI Process Manager
مدير عمليات FastCGI عالي الأداء لمعالجة طلبات خادم الويب في PHP.
للمراجعة
04 HTML HTML
HyperText Markup Language
لغة الترميز القياسية التي يولدها محرك PHP ويرسلها إلى متصفح العميل بعد التنفيذ.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم تعريف التعدادات الصرفة Pure Enums للتحقق من المخرجات.

  2. بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم التعدادات المدعومة بقيم ودالتا from و tryFrom وقارن مخرجات التنفيذ.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

8أسئلة 1أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي8 أسئلة تنتظرك
01

ما الفرق بين التعداد الصرف (Pure Enum) والتعداد المدعوم بقيم (Backed Enum) في PHP 8.1+؟

تحدد التعدادات المدعومة النوع : int أو : string وتوفر الخاصية $case->value ودالتي from() وtryFrom().

02

ماذا تُرجع الدالة OrderStatus::tryFrom("invalid_code") إذا لم تطابق القيمة أي حالة في التعداد المدعوم OrderStatus؟

تُرجع tryFrom() القيمة null عند عدم وجود تطابق، بينما تطلق from() خطأ ValueError.

03

أي عبارة مما يلي صحيحة حول الدوال والخصائص داخل التعداد (Enum) في PHP؟

يُسمح للتعدادات بالدوال والثوابت والواجهات، ويُمنع فيها تعريف الخصائص المتغيرة.

04

ماذا يفعل وسم الصنف بالكلمة المفتاحية readonly (مثل readonly class InvoiceDto) في PHP 8.2+؟

يجعل الصنف جميع خصائصه قابلة للإسناد مرة واحدة فقط ويمنع الخصائص الديناميكية.

05

في خطاف الخاصية في PHP 8.4: public string $code { set => strtoupper($value); }، ماذا يمثل المتغير $value؟

يمثل $value القيمة الممررة عند الإسناد، وتُخزن نتيجة التعبير داخل الخاصية.

06

ماذا تفرض صيغة الرؤية غير المتماثلة public private(set) int $balance = 0; في PHP 8.4؟

تسمح public بالقراءة العامة، بينما تقصر private(set) صلاحية الكتابة والتعديل على داخل الصنف نفسه.

07

ما الدالة الثابتة المدمجة التي تُرجع مصفوفة بجميع الحالات المعرّفة داخل أي تعداد Enum؟

يطبق كل تعداد في PHP تلقائياً الواجهة UnitEnum التي توفر الدالة الثابتة cases().

08

لماذا يجب أن تحمل كل خاصية داخل الصنف readonly نوع بيانات صريحاً (مثل string أو int أو mixed)؟

تبدأ الخصائص المحددة النوع بحالة غير مهيأة (uninitialized) حتى أول إسناد، وهو شرط عمل readonly.