مراجعة إعادة تعريف الدوال (Method Overriding)
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 33 من 91.
لقد تعلمت بالفعل عن تجاوز الأساليب (method overriding) في فصل الوراثة. الآن دعنا نستكشف كيف يرتبط ذلك بـ تعدد الأشكال (polymorphism) - أحد أقوى المفاهيم في البرمجة كائنية التوجه.
تعدد الأشكال (Polymorphism) يعني "أشكالاً متعددة". عندما تقوم بعمل override لـ method في child class، فإنك تعطي هذه الـ method شكلاً مختلفاً مع الحفاظ على الاسم نفسه. يحدث السحر عندما تتعامل مع objects من خلال الـ parent type الخاص بها:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()) . "\n";
echo makeAnimalSpeak(new Cat());
الناتج:
Woof!
Meow!تقبل الدالة makeAnimalSpeak() أي Animal. فهي لا تعرف ولا تهتم ما إذا كانت تستقبل Dog أو Cat. يقوم PHP تلقائيًا باستدعاء الطريقة (method) التي تم تجاوزها (overridden) بشكل صحيح بناءً على نوع الكائن الفعلي في وقت التشغيل.
هذا هو تعدد الأشكال (polymorphism) في الواقع.
يتيح لك هذا النهج كتابة كود مرن يعمل مع مجموعة من الكائنات المرتبطة دون معرفة أنواعها المحددة. يمكنك إضافة فئات (classes) حيوانات جديدة لاحقاً، وستعمل الوظيفة (function) معها تلقائياً.
نقطة رئيسية: يُمكّن تجاوز الدوال (Method overriding) تعدد الأشكال (polymorphism) من خلال السماح لفئات مختلفة بالاستجابة بشكل مختلف لنفس استدعاء الدالة، وهو ما يتم تحديده في وقت التشغيل بناءً على نوع الكائن الفعلي.
التحدي
سهللنقم ببناء نظام للآلات الموسيقية يوضح تعدد الأشكال (polymorphism) من خلال تجاوز الدوال (method overriding). ستقوم بإنشاء فئة أساسية Instrument وفئتين فرعيتين تنتج كل منهما صوتها الفريد — ثم تستخدم دالة واحدة لتشغيل أي آلة بشكل متعدد الأشكال.
ستقوم بتنظيم الكود الخاص بك عبر أربعة ملفات:
Instrument.php— أنشئ فئةInstrumentمع خاصية محمية$nameيتم تعيينها من خلال المنشئ (constructor). أضف دالةplay()تعيد"[name] makes a sound". يعمل هذا كالسلوك الأساسي الذي ستقوم الفئات الفرعية بتجاوزه.Guitar.php— أنشئ فئةGuitarترث منInstrument. قم بتضمين ملف الأب. يقبل المنشئ الاسم ويمرره إلى منشئ الأب. قم بتجاوز دالةplay()لتعيد"[name] strums a chord".Drum.php— أنشئ فئةDrumترث منInstrument. قم بتضمين ملف الأب. يقبل المنشئ الاسم ويمرره إلى منشئ الأب. قم بتجاوز دالةplay()لتعيد"[name] beats a rhythm".main.php— قم بتضمين ملفي Guitar و Drum. أنشئ دالة تسمىperformWithتقبل معاملًا من نوعInstrument(باستخدام تلميح النوع type-hinting) وتعيد نتيجة استدعاءplay()عليه. توضح هذه الدالة تعدد الأشكال — فهي تعمل مع أي نوع من الآلات من خلال تلميح نوع الفئة الأب.
ستتلقى مدخلين: اسم للجيتار واسم للطبلة. أنشئ كائن Guitar وكائن Drum بهذه الأسماء. مرر كل منهما إلى دالة performWith() الخاصة بك واطبع النتائج — الجيتار أولاً، ثم الطبلة، كل منهما في سطر مستقل.
لاحظ كيف تقبل performWith() أي Instrument، ومع ذلك يقوم PHP تلقائيًا باستدعاء دالة play() المتجاوزة الصحيحة بناءً على نوع الكائن الفعلي في وقت التشغيل. هذا هو تعدد الأشكال (polymorphism) في أبهى صوره!
ورقة مرجعية
تعني تعدد الأشكال (Polymorphism) "أشكالاً متعددة"، وهي تسمح بمعاملة كائنات من فئات مختلفة من خلال نوعها الأب مع الحفاظ على سلوكها الخاص.
عندما تقوم بإعادة تعريف (override) دالة في الفئات الأبناء، يقوم PHP تلقائياً باستدعاء النسخة الصحيحة بناءً على نوع الكائن الفعلي في وقت التشغيل:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()); // Woof!
echo makeAnimalSpeak(new Cat()); // Meow!
تقبل الدالة makeAnimalSpeak() أي نوع من الـ Animal من خلال تلميح النوع (type hint) للمعامل الخاص بها. هي لا تحتاج لمعرفة الفئة المحددة - يحدد PHP أي دالة تمت إعادة تعريفها يجب استدعاؤها في وقت التشغيل بناءً على نوع الكائن الفعلي.
يتيح ذلك كتابة كود مرن يعمل مع مجموعة من الكائنات المرتبطة ببعضها دون معرفة أنواعها المحددة. يمكن إضافة فئات أبناء جديدة لاحقاً وستعمل تلقائياً مع الدوال الموجودة.
جرّب بنفسك
<?php
// تضمين ملفات الآلات
require_once 'Guitar.php';
require_once 'Drum.php';
// قراءة المدخلات
$guitarName = trim(fgets(STDIN));
$drumName = trim(fgets(STDIN));
// TODO: إنشاء دالة تسمى performWith تقوم بـ:
// - تقبل معامل من نوع Instrument (استخدم تلميح النوع: Instrument $instrument)
// - تعيد نتيجة استدعاء ()play على الآلة
// TODO: إنشاء Guitar باستخدام guitarName$ و Drum باستخدام drumName$
// TODO: تمرير كل منهما إلى ()performWith وطباعة النتائج (الغيتار أولاً، ثم الطبل)
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
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)