التحميل الزائد في PHP

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

تقديم ميزة التحميل الزائد في PHP القدرة على إنشاء الخصائص والتوابع بصورة ديناميكية، وتعالج هذه العناصر الديناميكية بواسطة التوابع السحرية (magic methods) التي يمكن استخدامها في الصنف لأداء العديد من الوظائف.

تنفّذ توابع التحميل الزائد عند التفاعل مع الخصائص أو التوابع غير المصرّح عنها أو غير المرئية ضمن النطاق الحالي. سيستخدم هذا القسم مصطلحي "خاصية يتعذر الوصول إليها" و"تابع يتعذر الوصول إليه" للإشارة إلى حالة التصريح وقابلية الرؤية هذه.

يجب تعريف جميع توابع التحميل الزائد كتوابع من نوع public.

ملاحظة: لا يمكن تمرير المعاملات الخاصة بهذه التوابع السحرية بالمرجعية.

ملاحظة: يختلف مفهوم "التحميل الزائد" في PHP عنه في معظم اللغات البرمجية كائنية التوجه، إذ يسمح التحميل الزائد بوجود توابع متعدّدة تحمل الاسم ذاته ولكنّها تختلف في عدد ونوع المعاملات.

سجل التغييرات

الإصدار الوصف
5.3.0 إضافة التابع ‎__callStatic()‎، وإضافة تحذير لفرض قابلية الرؤية من نوع public والتصريح غير السكوني.
5.1.0 إضافة التابعين ‎__isset()‎ و ‎__unset()‎. إضافة الدعم للتابع ‎__get()‎ للتحميل الزائد للخصائص من نوع private.
5.0.0 إضافة التابع ‎__get()‎.

التحميل الزائد للخواص

public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )

يعمل التابع ‎__set()‎ عند كتابة البيانات إلى خاصية يتعذر الوصول إليها.

يستخدم التابع ‎__get()‎ في قراءة البيانات من خاصية يتعذر الوصول إليها.

ينطلق التابع ‎__isset()‎ عن طريق استدعاء الدالة isset()‎ أو empty()‎ على خاصية يتعذر الوصول إليها.

تستخدم الدالة ‎__unset()‎ عند استخدام الدالة unset()‎ مع خاصية يتعذر الوصول إليها.

المعامل ‎$name هو اسم المتغير الذي يجري التعامل معه، أما المعامل ‎$value في التابع ‎__set()‎ فيحدد قيمة الاسم الذي يجب أن تحمله الخاصية.

يعمل التحميل الزائد للخصائص ضمن سياق الكائن فقط، ولا يمكن لهذه التوابع السحرية أن تعمل في سياق ساكن؛ لهذا لا يجوز التصريح عن هذه التوابع كتوابع من نوع static. ومنذ الإصدار 5.3.0 تطلق اللغة تحذيرًا في حال التصريح السكوني عن إحدى هذه التوابع.

ملاحظة: تتجاهل اللغة القيمة المعادة من التابع ‎__set()‎ بسبب طريقة معالجتها لعامل الإسناد. كذلك الأمر بالنسبة للتابع ‎__get()‎ والذي لا يستدعى على الإطلاق عند ربط عمليات الإسناد بالصورة التالية:

 $a = $obj->b = 8;

المثال 1: التحميل الزائد للخصائص باستخدام التوابع ‎__get()‎ و ‎__set()‎ و ‎__isset()‎ و ‎__unset()

<?php
class PropertyTest
{
    //  موقع بيانات التحميل الزائد
    private $data = array();

    //  لم يستخدم التحميل الزائد على الخاصية المصرح عنها
    public $declared = 1;


    //  يُستخدم التحميل الزائد على هذه الخاصية عند الوصول إليها من خارج الصنف فقط
    private $hidden = 2;

    public function __set($name, $value)
    {
        echo "Setting '$name' to '$value'\n";
        $this->data[$name] = $value;
    }

    public function __get($name)
    {
        echo "Getting '$name'\n";
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        $trace = debug_backtrace();
        trigger_error(
            'Undefined property via __get(): ' . $name .
            ' in ' . $trace[0]['file'] .
            ' on line ' . $trace[0]['line'],
            E_USER_NOTICE);
        return null;
    }

    //  منذ الإصدار 5.1.0
    public function __isset($name)
    {
        echo "Is '$name' set?\n";
        return isset($this->data[$name]);
    }

    //  منذ الإصدار 5.1.0
    public function __unset($name)
    {
        echo "Unsetting '$name'\n";
        unset($this->data[$name]);
    }

    //  ليس تابعًا سحريًا وقد استخدم هنا كمثال فقط
    public function getHidden()
    {
        return $this->hidden;
    }
}


echo "<pre>\n";

$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "\n\n";

var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";

echo $obj->declared . "\n\n";

echo "Let's experiment with the private property named 'hidden':\n";
echo "Privates are visible inside the class, so __get() not used...\n";
echo $obj->getHidden() . "\n";
echo "Privates not visible outside of class, so __get() is used...\n";
echo $obj->hidden . "\n";
?>

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

Setting 'a' to '1'
Getting 'a'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'


Notice:  Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29

التحميل الزائد للتوابع

public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )

ينطلق التابع ‎__call()‎ عند استخدام توابع يتعذر الوصول إليها في سياق الكائن.

ينطلق التابع ‎__callStatic()‎ عند استخدام توابع يتعذر الوصول إليها في سياق ساكن.

المعامل ‎$name هو اسم التابع الذي يجري استدعاؤه، أما المعامل ‎$arguments فهو عبارة عن مصفوفة عددية تحتوي على المعاملات الممرّرة إلى التابع الذي يحمل الاسم ‎$name.

المثال 2: التحميل الزائد للتوابع باستخدام التابعين ‎__call()‎ و ‎__callStatic()

<?php
class MethodTest
{
    public function __call($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    //  منذ الإصدار 5.3.0
    public static function __callStatic($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');
// منذ الإصدار 5.3.0
?>

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

Calling object method 'runTest' in object context
Calling static method 'runTest' in static context

مصادر