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

مراجعة إعادة تعريف الدوال (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) من خلال السماح لفئات مختلفة بالاستجابة بشكل مختلف لنفس استدعاء الدالة، وهو ما يتم تحديده في وقت التشغيل بناءً على نوع الكائن الفعلي.

challenge icon

التحدي

سهل

لنقم ببناء نظام للآلات الموسيقية يوضح تعدد الأشكال (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 وطباعة النتائج (الغيتار أولاً، ثم الطبل)

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

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

جميع دروس Object Oriented Programming