الربط الاستاتيكي المتأخر (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:: عندما تريد من الفئات الابنة أن ترث السلوك الثابت وتخصّصه بشكل صحيح.
التحدي
سهللنبنِ نظام سجلّ للنماذج يوضّح قوة الربط الثابت المتأخر. ستنشئ 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 المصنع inheritedcreate()لإنشاء 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()
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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 Collection3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)تدرّب بنفسك: مترجم PHP عبر الإنترنت