التوابع السحرية في PHP

من موسوعة حسوب
< PHP
اذهب إلى: تصفح، ابحث

التوابع السحرية في أصناف PHP هي ‎__construct()‎ و ‎__destruct()‎ و ‎__call()‎ و ‎__callStatic()‎ و ‎__get()‎ و ‎__set()‎ و ‎__isset()‎ و ‎__unset()‎‎ و ‎__sleep()‎ و ‎__wakeup()‎ و ‎__toString()‎ و ‎__invoke()‎ و ‎_‎_set_state()‎ و ‎__clone()‎ و ‎__debugInfo()‎. ولا يمكنك استخدام دوالّ تحمل هذه الأسماء في أي صنف ما لم تكن ترغب في الاستفادة من الوظيفة السحرية التي تتمتّع بها.

تحذير: تحجز PHP جميع الدوال التي تبدأ بالرمز __ كدوال سحرية؛ لذا ينصح بعدم تسمية دوالك الخاصة بأسماء تبدأ بهذا الرمز ما لم تكن ترغب في استخدام الدوال السحرية.

__sleep()‎ و ‎__wakeup()

public array __sleep ( void )
void __wakeup ( void )

تتأكد الدالة serialize()‎ من امتلاك الصنف للتابع السحري ‎__sleep()‎، فإن كان موجودًا فستُنفَّذ تلك الدالة قبل إجراء أيّ عملية سَلْسَلَة (serialization). يمكن لهذه الدالة أن تنظّف الكائن ومن المفترض أن تعيد مصفوفة تحمل أسماء جميع المتغيرات الخاصة بالكائن الذي ستجرى عليه عملية السَلْسَلَة. وإن لم يعد التابع أي شيء فإنّ السلسلة تجري على NULL ويطلق خطأ من نوع E_NOTICE.

ملاحظة: لا يمكن للتابع ‎__sleep()‎ أن يعيد أسماء الخصائص من نوع private في الصنف الأب. يؤدي القيام بذلك إلى إطلاق خطأ من المستوى E_NOTICE، ويمكن بدلًا من ذلك استخدام الواجهة Serializable.

إنّ الهدف من استخدام ‎__sleep()‎ هو تنفيذ البيانات المعلّقة أو إجراء مهام التنظيف المشابهة، وهذا التابع مفيد في حال وجود كائنات كبيرة جدًّا لا تحتاج إلى حفظها بالكامل.

يعمل التابع unserialize()‎ على التأكد من وجود الدالة السحرية ‎__wakeup()‎، وفي حال وجودها، يمكن لهذه الدالة إعادة هيكلة أي مصدر قد يمتلكه الكائن.

إنّ الهدف من استخدام ‎__wakeup()‎ هو إعادة إجراء الاتصال مع قواعد البيانات التي يمكن أن تكون قد قطعت أثناء عملية السلسلة إضافة إلى إجراء مهامّ إعادة تأهيل أخرى.

المثال 1: التابعان sleep و wakeup

<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;
    
    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }
    
    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }
    
    public function __sleep()
    {
        return array('dsn', 'username', 'password');
    }
    
    public function __wakeup()
    {
        $this->connect();
    }
}?>

‎__toString()‎

public string __toString ( void )

يتيح التابع ‎__toString()‎ للصنف اختيار طريقة تفاعله في حال عومِل معاملة السلاسل النصية. فعلى سبيل المثال، ما الذي ستطبعه العبارة echo $obj. يجب أن يعيد هذا التابع سلسلة نصية وإلا فستطلق اللغة خطأ من المستوى E_RECOVERABLE_ERROR.

تحذير: لا يمكنك إطلاق استثناء من داخل التابع ‎__toString()‎ وسيؤدي القيام بذلك إلى إطلاق خطأ من نوع fatal.

المثال 2: مثال بسيط على استخدام التابع ‎__toString()

<?php
// التصريح عن صنف بسيط
class TestClass
{
    public $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        return $this->foo;
    }
}

$class = new TestClass('Hello');
echo $class;
?>

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

Hello

يجدر الانتباه إلى أنّ التابع ‎__toString()‎ قبل الإصدار 5.2.0 كان يستدعى عند دمجه مباشرة مع echo أو print فقط، ولكن منذ الإصدار 5.2.0 أصبح بالإمكان استدعاء هذا التابع في أي سياق نصّي (مثل: printf()‎ مع المعدِّلات ‎%s) وليس في أي سياق من أنواع أخرى (مثل المعدِّلات ‎%d). في الإصدار 5.2.0 يؤدي تحويل الكائنات إلى سلاسل نصّية دون استخدام التابع ‎__toString()‎ إلى إطلاق خطأ من المستوى E_RECOVERABLE_ERROR.

‎__invoke()‎

mixed __invoke ([ $... ] )

تستدعى الدالة ‎__invoke()‎ عندما تحاول الشيفرة استدعاء كائن كدالة.

ملاحظة: هذه الميزة متوفّرة في الإصدار 5.3.0 وما بعده من PHP.

المثال 3: استخدام التابع ‎__invoke()

<?php
class CallableClass
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>

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

int(5)
bool(true)

‎__set_state()‎

static object __set_state ( array $properties )
يستدعى هذا التابع الساكن عند تصدير الأصناف باستخدام الدالة var_export()‎ في الإصدار 5.1.0 من PHP وما بعده.

يأخذ هذا التابع معاملًا واحدًا وهو مصفوفة تتضمن الخائص المصدَّرة على هيئة ‎array('property' => value, ...)‎.

المثال 4: استخدام ‎__set_state()‎ (الإصدار 5.1.0 وما بعده من PHP)

<?php

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array)
    // في الإصدار 5.1.0 وما بعده
    {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
                                            //    'var1' => 5,
                                            //    'var2' => 'foo',
                                            // ));
var_dump($b);

?>

يعطي المثال السابق النتائج التالية:

object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}

ملاحظة: عند تصدير الكائن لا تتحقّق الدالة var_export ممّا إذا كان التابع ‎__set_state()‎ قد استخدم بواسطة كائن الصنف؛ لذا فإنّ إعادة استيراد مثل هذه الكائنات سينتهي بالفشل إن لم يُستخدم التابع ‎__set_state()‎، ويؤثّر هذا الأمر بشكل خاصّ على بعض الأصناف الداخلية. تقع مسؤولية التحقّق من الكائنات التي سيعاد استيرادها والأصناف التي ستستخدم التابع ‎__set_state()‎ على كاهل المبرمج.

__debugInfo()‎

array __debugInfo ( void )

يستدعى هذا التابع بواسطة الدالة var_dump()‎ عند إسقاط dumping الكائن للحصول على الخصائص التي يجب عرضها. إن لم يُعرّف التابع على الكائن فستعرض الخصائص بجميع أنواعها public و protected و private.

أضيفت هذه الميزة إلى الإصدار 5.6.0 من PHP.

المثال 5: استخدام ‎__debugInfo()‎

<?php
class C {
    private $prop;

    public function __construct($val) {
        $this->prop = $val;
    }

    public function __debugInfo() {
        return [
            'propSquared' => $this->prop ** 2,
        ];
    }
}

var_dump(new C(42));
?>

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

object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}

مصادر