تجريد الأصناف في PHP

من موسوعة حسوب
< PHP

يقدّم الإصدار الخامس من اللغة الأصناف والتوابع المجرّدة (abstract classes and methods). لا يمكن تهيئة الأصناف المجرّدة، وإذا احتوى الصنف على تابع مجرّد واحدٍ على الأقل فيجب أن يكون الصنف مجردًا أيضًا. تصرّح الأصناف المجرّدة ببساطة عن توقيع التابع (method's signature، أي اسم الدالة وعدد ونوع معاملاتها)، ولا يمكنها تعريف محتويات تلك التوابع (implementation).

عندما يرث صنفٌ ما من صنفٍ مجرّد، يجب تعريف جميع التوابع المجرّدة في الصنف الأب ضمن الصنف الابن، إضافة إلى وجوب تعريف هذه الأصناف بنفس مستوى قابلية الرؤية (أو بمستوى أقل محدودية). فعلى سبيل المثال، إن كان التابع المجرّد من نوع protected فإن تطبيق الدالة (أي تعريفها وإضافة الشيفرة الخاصة بها) يجب أن يكون من نوع protected أو public، ولا يمكن أن يكون من نوع private. بالإضافة إلى ذلك، يجب أن تتطابق تواقيع التوابع أيضًا، بمعنى أنّ التلميح عن النوع (type hint) وعدد المعاملات المطلوبة يجب أن يكون متشابهًا. فمثلًاً، إن تضمن تعريف الصنف الابن معاملًا اختياريًا، في حين أن توقيع التابع المجرد لا يتضمن مثل هذا المعامل، فلا وجود لأي تعارض في التوقيع. ينطبق هذا الأمر أيضًا على التوابع البانية في الإصدار 5.4 من اللغة، أما في الإصدارات السابقة فيمكن أن يحدث اختلاف في توقيعات التوابع البانية.

المثال 1: مثال على صنف مجرد

<?php
abstract class AbstractClass
{
    // يجب توسيع الصنف لتعريف هذا التابع
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // تابع مشترك
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";
?>

تعطي الشيفرة السابقة المخرجات التالية:

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

المثال 2: مثال على صنف مجرّد

<?php
abstract class AbstractClass
{
    // يحتاج التابع المجرد إلى تعريف المتغيرات المطلوبة فقط
    abstract protected function prefixName($name);

}

class ConcreteClass extends AbstractClass
{

    // يمكن للصنف الابن أن يعرّف معاملات اختياري غير موجودة في توقيع التابع الأب
    public function prefixName($name, $separator = ".") {
        if ($name == "Pacman") {
            $prefix = "Mr";
        } elseif ($name == "Pacwoman") {
            $prefix = "Mrs";
        } else {
            $prefix = "";
        }
        return "{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass;
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>

تعطي الشيفرة السابقة النتائج التالية:

Mr. Pacman
Mrs. Pacwoman

تعمل الشيفرة القديمة التي لا توجد فيها أصناف معرّفة من قبل المستخدم أو دوال تحمل الاسم 'abstract' دون أي تعديلات.

مصادر