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

الربط الاستاتيكي المتأخر (Late Static Binding)

جزء من قسم البرمجة كائنية التوجه في رحلة PHP على Coddy. الدرس 36 من 91.

عند استخدام self:: في class الأصلية، فإنها تشير دائمًا إلى class التي كُتبت فيها، وليس إلى class المستخدمة فعليًا. قد يتسبب ذلك في سلوك غير متوقع عند التوريث. يحل الربط الساكن المتأخر هذه المشكلة باستخدام الكلمة المفتاحية static::.

تأمل هذا المثال حيث لا تعمل self:: كما هو متوقع:

<?php
class ParentClass {
    public static function create() {
        return new self();
    }
    
    public static function getClassName() {
        return self::class;
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();

المخرجات:

ParentClass
ParentClass

على الرغم من أننا استدعينا ChildClass::create()، حصلنا على كائن ParentClass لأن self:: يتم حلّه في وقت الترجمة. لنستخدم الآن static:: بدلًا من ذلك:

<?php
class ParentClass {
    public static function create() {
        return new static();
    }
    
    public static function getClassName() {
        return static::class;
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();

المخرجات:

ChildClass
ChildClass

باستخدام static::، تنتظر PHP حتى وقت التشغيل لتحديد الفئة التي يجب استخدامها. يُسمّى هذا الارتباط "المتأخر" لأن القرار يتأخر. وهو أمر أساسي لأساليب factory ولأي أسلوب static يجب أن يحترم الوراثة.

النقطة الأساسية: استخدم static:: بدلًا من self:: عندما تريد من الفئات الابنة أن ترث السلوك الثابت وتخصّصه بشكل صحيح.

challenge icon

التحدي

سهل

لنبنِ نظام سجلّ للنماذج يوضّح قوة الربط الثابت المتأخر. ستنشئ class أساسية باسم Model مع method مصنع يمكن للفئات الابنة inherited منها، وبفضل static:: ستنشئ كل فئة ابنة instances من نفسها بشكل صحيح بدلاً من الفئة الأصلية.

ستنظّم الكود الخاص بك عبر أربعة ملفات:

  • Model.php: أنشئ class أساسية باسم Model مع property static محمية $tableName مضبوطة على "models". أضف method static باسم create() تستخدم new static() لإرجاع instance جديدة من أي class استدعتها. أضف method static أخرى باسم getTable() تُرجع static::$tableName. وأخيرًا، أضف method باسم describe() تُرجع "[ClassName] from table [tableName]" باستخدام static::class وstatic::$tableName.
  • User.php: أنشئ class باسم User تمتد من Model. ضمّن الملف الأب. Override للـ property static $tableName لتصبح "users". ترث class جميع methods من Model دون أي تغييرات.
  • Product.php: أنشئ class باسم Product تمتد من Model. ضمّن الملف الأب. Override للـ property static $tableName لتصبح "products". ومرة أخرى، ترث class جميع methods من الفئة الأصلية.
  • main.php: ضمّن ملفَي User وProduct. استخدم method المصنع inherited create() لإنشاء instances من كل من User وProduct. لكل instance، استدعِ describe() واطبع result في سطر مستقل. ثم اطبع اسم الجدول لكل class باستخدام User::getTable() وProduct::getTable()، بحيث يكون كل منهما في سطر مستقل.

يكمن السحر هنا في أن methods create() وgetTable() معرّفة فقط في class الأصلية Model، ومع ذلك فإنها تعمل بشكل صحيح مع الفئات الابنة لأن static:: يؤخر الربط حتى وقت التشغيل. عند استدعاء User::create()، تنشئ PHP instance من User، وليس instance من Model، لأن static:: تشير إلى class التي تم استدعاؤها فعليًا.

يجب أن يعرض output أربعة أسطر: الوصف الخاص بـ instance من User، والوصف الخاص بـ instance من Product، واسم جدول User، واسم جدول Product.

جرّب بنفسك

<?php

require_once 'User.php';
require_once 'Product.php';

// TODO: استخدم طريقة المصنع create() الموروثة لإنشاء مثيل User

// TODO: استخدم طريقة المصنع create() الموروثة لإنشاء مثيل Product

// TODO: استدعِ describe() على مثيل User واطبع النتيجة

// TODO: استدعِ describe() على مثيل Product واطبع النتيجة

// TODO: اطبع User::getTable()

// TODO: اطبع Product::getTable()

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

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

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

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