call()__ وcallStatic()__
يُستدعى التابعين __call()
و__callStatic()
عندما تريد استدعاء تابع كائن غير موجود في سياق تابع أو سياق ساكن.
في الشيفرة التالية يُستدعى التابع __call()
عندما يحاول شخص ما استدعاء تابع في سياق كائن غير موجود مثل $foo->method($arg, $arg1);
، سيحتوي الوسيط الأول على اسم التابع وهو method
في مثالنا وسيحتوي الوسيط الثاني على قيم $arg
و$arg1
كمصفوفة.
ويُستدعى التابع __callStatic()
من محتوى ساكن عند استدعاء تابع ساكن غير موجود، مثلًا Foo::buildSomethingCool($arg);
، سيحتوي الوسيط الأول على اسم التابع وهو buildSomethingCool
في مثالنا ويحتوي الوسيط الثاني على قيمة $arg
في مصفوفة. لاحظ أنّ بصمة هذا التابع مختلفة (يتطلب الكلمة المفتاحية static)، هذا التابع لم يكن موجودًا قبل الإصدار PHP 5.3.
class Foo { public function __call($method, $arguments) { // (1) $snakeName = CaseHelper::camelToSnake($method); // الحصول على البادئة $subMethod = substr($snakeName, 0, 3); // إسقاط اسم التابع $propertyName = substr($snakeName, 4); switch ($subMethod) { case "get": return $this->data[$propertyName]; case "set": $this->data[$propertyName] = $arguments[0]; break; case "has": return isset($this->data[$propertyName]); default: throw new BadMethodCallException("Undefined method $method"); } } public static function __callStatic($method, $arguments) { // يمكن استخدام هذا التابع عندما تحتاج شيء ما مثل مصنع عام أو شيء ما آخر print_r(func_get_args()); } }
في الموضع (1) نفعل شيء ما مع المعلومات مثل زيادة التحميل أو شيء عام، فمثلًا لنفرض أننا نكتب صنفًا عامًا يحمل بعض البيانات ويسمح للمستخدم بأن يجلبها ويضبطها باستخدام التوابع الجالب والضابط، وكان لدينا الصنف CaseHelper
يساعد على تحويل نمط سنام الجمل (camelCase) إلى نمط الثعبان (snake_case). هذا التابع مبسّط لذا لا يتحقق من صلاحية الاسم أو عدمها.
مثال:
$instance = new Foo(); $instance->setSomeState("foo"); var_dump($instance->hasSomeState()); // bool(true) var_dump($instance->getSomeState()); // string "foo" Foo::exampleStaticCall("test"); /* Array ( [0] => exampleCallStatic [1] => test ) */
get()__ و__set() و__isset() و__unset()
كلما حاولت استعادة حقل معين من صنف كما في الشيفرة:
$animal = new Animal(); $height = $animal->height;
تستدعي PHP التابع السحري __get($name)
ويكون $name
هو "height" في حالتنا. كتابة حقل ما من الصنف كالتالي:
$animal->height = 10;
ستستدعي التابع السحري __set($name, $value),
ويكون $name
هو "height" و$value
هو 10.
لدينا في PHP أيضًا تابعين مدمجين هما isset()
الذي يتحقق من وجود متغير، وunset()
الذي يدمر متغير.
إنّ الشيفرة التالية:
isset($animal->height);
ستستدعي الدالة __isset($name)
على ذلك الكائن، كما أنّ إزالة تعيين متغير كما في الشيفرة:
unset($animal->height);
ستستدعي الدالة __unset($name)
على ذلك الكائن.
تستعيد PHP الحقل كما هو مخزن في الصنف عندما لاتعرّف هذه التوابع في صنفك، لكن يمكنك تجاوز هذه التوابع لإنشاء أصناف يمكنها أن تحمل بيانات مثل المصفوفة لكنها قابلة للاستخدام ككائن:
class Example { private $data = []; public function __set($name, $value) { $this->data[$name] = $value; } public function __get($name) { if (!array_key_exists($name, $this->data)) { return null; } return $this->data[$name]; } public function __isset($name) { return isset($this->data[$name]); } public function __unset($name) { unset($this->data[$name]); } } $example = new Example(); // وقيمتها 15 $data في المصفوفة 'a' تخزين $example->a = 15; // $data من المصفوفة 'a' استعادة مفتاح المصفوفة echo $example->a; // 15 // null محاولة استعادة مفتاح غير موجود في المصفوفة تُعيد echo $example->b; // لا يطبع شيء if (isset($example->a)) { unset($example->a)); }
الدالة empty() والتوابع السحرية
لاحظ أنّ استدعاء الدالة empty() على خاصيّة صنف ستستدعي الدالة __isset($name)
حسب ما ورد في توثيق PHP: empty()
هي المكافئ المختصر للشيفرة:
!isset($var) || $var == false
__construct() و__destruct()
__construct()
هو التابع السحري الأشهر في PHP لأنّه يُستخدم لضبط صنف عند تهيئته، أما التابع العكسي له __destruct()
فإنّه يُستدعى عندما لا يوجد مراجع متبقية للكائن الذي أنشأته أو عندما تفرض حذفه وعندها ستقوم مجموعة المهملات بتنظيف الكائن عن طريق استدعاء الهادم أولًا ثمّ حذفه من الذاكرة:
class Shape { public function __construct() { echo "Shape created!\n"; } } class Rectangle extends Shape { public $width; public $height; public function __construct($width, $height) { parent::__construct(); $this->width = $width; $this->height = $height; echo "Created {$this->width}x{$this->height} Rectangle\n"; } public function __destruct() { echo "Destroying {$this->width}x{$this->height} Rectangle\n"; } } function createRectangle() { // (1) $rectangle = new Rectangle(20, 50); // (2) } createRectangle(); // (3) // (4) unset(new Rectangle(20, 50));
في الموضع (1) ستستدعي تهيئة الكائن الباني مع الوسطاء المحددين.
في الموضع (2) سيُطبع 'Shape Created' ثم 'Created 20x50 Rectangle'.
في الموضع (3) سيُطبع 'Destroying 20x50 Rectangle' لأنّ الكائن $rectangle
هو كائن محلي بالنسبة للدالة createRectangle
لذا عندما ينتهي نطاق الدالة سيُدمَّر الكائن ويُستدعى هادمه.
في الموضع (4) سيُستدعى هادم الكائن عند استخدام الدالة unset
.
__toString()
يُستدعى التابع __toString()
عندما يُعامل الكائن على أنّه سلسلة نصية، ويعيد سلسلة نصية تمثّل الصنف:
class User { public $first_name; public $last_name; public $age; public function __toString() { return "{$this->first_name} {$this->last_name} ($this->age)"; } } $user = new User(); $user->first_name = "Chuck"; $user->last_name = "Norris"; $user->age = 76; // في سياق سلسلة $user كلما اُستخدم الكائن __toString() سيُستدعى التابع echo $user; // Chuck Norris (76) // Selected user: Chuck Norris (76) :أصبحت قيمة السلسلة النصية $selected_user_string = sprintf("Selected user: %s", $user); // __toString() التحويل إلى سلسلة نصية يستدعي أيضًا $user_as_string = (string) $user;
__clone()
يُستدعَى التابع __clone
باستخدام الكلمة المفتاحية clone
، ويستخدم لمعالجة حالة كائن عند النسخ بعد أن يكون الكائن قد نُسخَ فعلًا.
class CloneableUser { public $name; public $lastName; // "Copy " سيُستدعى هذا التابع بعامل النسخ ويضيف قبل خاصيّات الاسم والاسم الأخير الكلمة public function __clone() { $this->name = "Copy " . $this->name; $this->lastName = "Copy " . $this->lastName; } }
مثال:
$user1 = new CloneableUser(); $user1->name = "John"; $user1->lastName = "Doe"; // __clone تنفيذ التابع السحري $user2 = clone $user1; echo $user2->name; // Copy John echo $user2->lastName; // Copy Doe
__invoke()
يُستدعى هذا التابع السحري عندما يحاول المستخدم استدعاء كائن كدالة، قد تتضمن حالات الاستخدام الممكنة بعض الطرق مثل البرمجة الوظيفية أو بعض ردود النداء.
سيُستدعى التابع في الشيفرة التالية إذا نُفِّذ الكائن كدالة: $invokable();
وستمرر الوسائط كما في استدعاء التابع العادي:
class Invokable { public function __invoke($arg, $arg, ...) { print_r(func_get_args()); } }
مثال:
$invokable = new Invokable(); $invokable([1, 2, 3]); /* Array ( [0] => 1 [1] => 2 [2] => 3 ) */
__sleep() و__wakeup()
يرتبط التابعان __sleep
و__wakeup
بعملية السَلسَلة، تتحقق الدالة serialize
إذا كان للصنف تابع __sleep
، إذا كان موجودًا سيُنفَّذ قبل أي سَلسَلة ويُفترض أن يعيد مصفوفة من أسماء كل المتغيرات للكائن الذي يجب أن يُسلسَل.
وسيُنفَّذ التابع __wakeup
بدوره من قبل الدالة unserialize
إذا وُجد في الصنف، ويهدف إلى إعادة إنشاء الموارد والأشياء الأخرى التي نحتاج تهيئتها بعد إلغاء التسلسل.
في الشيفرة التالية سيُنفَّذ التابع السحري __sleep
من قِبل الدالة serialize
ولاحظ أنّ $dbConnection
مُستبعد، وسيُنفَّذ التابع السحري __wakeup
من قِبل الدالة unserialize
، لنفرض مثلًا أنّ $this->c
الذي لم يُسَلسَل هو نوع من الاتصال بقاعدة البيانات سيُعيد الاتصال عندما نستخدم تابع الاستيقاظ.
class Sleepy { public $tableName; public $tableFields; public $dbConnection; public function __sleep() { // فقط $this->tableNameو $this->tableFields سيُسَلسَل return ['tableName', 'tableFields']; } public function __wakeup() { // الاتصال بقاعدة البيانات الافتراضية وتخزين المُعالج/المُغلِّف فيها // $this->dbConnection $this->dbConnection = DB::connect(); } }
__debugInfo()
يُستدعى هذا التابع من قِبل الدالة var_dump()
عند تفريغ كائن للحصول على الخاصيّات التي يجب عرضها، إذا لم يُعرَّف التابع على الكائن ستُعرَض كل الخاصيّات العامة والمحمية والخاصة.
class DeepThought { public function __debugInfo() { return [42]; } }
الإصدار PHP ≤ 5.6
var_dump(new DeepThought());
خرج الشيفرة السابقة:
class DeepThought#1 (0) { }
الإصدار PHP ≥ 5.6
var_dump(new DeepThought());
خرج الشيفرة السابقة:
class DeepThought#1 (1) { public ${0} => int(42) }
ترجمة -وبتصرف- للفصل [Magic Methods] من كتاب PHP Notes for Professionals book
اقرأ أيضًا
- المقال التالي: معالجة الملفات والبيانات المرمزة بترميز UTF-8 في PHP
- المقال السابق: مدخل إلى الملحن composer: مدير الاعتماديات والحزم في PHP
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.