__call و __callStatic
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 47 من 91.
تماماً كما تعترض __get() و __set() الوصول إلى الخصائص، تعترض الطريقتان __call() و __callStatic() استدعاءات الدوال. يتم تفعيلها عندما تقوم باستدعاء دالة غير موجودة أو غير قابلة للوصول في كائن أو فئة.
تتعامل الدالة __call() مع استدعاءات الأساليب الخاصة بالكائنات (instance method calls). وهي تستقبل اسم الدالة ومصفوفة من الوسائط:
<?php
class Messenger {
public function __call(string $name, array $arguments): string {
return "Called '$name' with: " . implode(", ", $arguments);
}
}
$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");
المخرجات:
Called 'sendEmail' with: Hello, Worldلاستدعاءات الأساليب الساكنة (static method calls)، استخدم __callStatic(). لاحظ أنه يجب التصريح عنها كـ static:
<?php
class QueryBuilder {
public static function __callStatic(string $name, array $arguments): string {
if (str_starts_with($name, "findBy")) {
$field = substr($name, 6);
return "Finding by $field: " . $arguments[0];
}
return "Unknown method: $name";
}
}
echo QueryBuilder::findByEmail("test@example.com");
المخرجات:
Finding by Email: test@example.comتعد هذه الطرق السحرية (magic methods) قوية لإنشاء واجهات برمجة تطبيقات (APIs) انسيابية، أو تنفيذ إعادة توجيه الطرق (method forwarding)، أو بناء بناة استعلامات ديناميكية حيث تترجم أسماء الطرق إلى عمليات قاعدة بيانات. فهي تتيح لكائناتك الاستجابة بذكاء لأي استدعاء لطريقة، حتى تلك التي لم تقم بتعريفها صراحة.
التحدي
سهللنقم ببناء عميل API ديناميكي يستخدم الطرق السحرية (magic methods) للتعامل مع استدعاءات الطرق بمرونة. ستقوم بإنشاء فئة تعترض كلاً من استدعاءات طرق الكائنات (instance methods) والطرق الثابتة (static methods)، وترجمتها إلى استجابات تشبه استجابات API ذات مغزى دون تحديد كل طريقة بشكل صريح.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
ApiClient.php— أنشئ فئةApiClientتحاكي تفاعلات API باستخدام الطرق السحرية. يجب أن تحتوي فئتك على خاصية خاصة$baseUrlيتم تعيينها من خلال المنشئ (constructor). قم بتنفيذ طريقتين سحريتين:__call()— تتعامل مع استدعاءات طرق الكائنات. عندما يتم استدعاء طريقة تبدأ بـget(مثلgetUsersأوgetPosts)، استخرج اسم المورد (الجزء الذي يلي "get") وأعد"GET [baseUrl]/[resource]: [arguments joined by comma]". يجب تحويل اسم المورد إلى أحرف صغيرة. إذا كانت الطريقة لا تبدأ بـ "get"، فأعد"Unknown action: [methodName]".__callStatic()— تتعامل مع استدعاءات الطرق الثابتة. عندما يتم استدعاء طريقة تبدأ بـcreate(مثلcreateUser)، استخرج اسم المورد وأعد"POST /[resource]: [arguments joined by comma]". يجب أن يكون اسم المورد بأحرف صغيرة. بالنسبة للطرق التي تبدأ بـdelete، أعد"DELETE /[resource]: [first argument]". لأي طريقة أخرى، أعد"Static action not supported: [methodName]".
main.php— قم بتضمين ملف ApiClient. ستتلقى ثلاثة مدخلات: عنوان URL أساسي، ومعرف مورد، وقيمة. أنشئ مثيلاً منApiClientباستخدام عنوان URL الأساسي. ثم اطبع أربعة أسطر:- استدعِ طريقة
getديناميكية باستخدام معرف المورد كلاحقة لاسم الطريقة (على سبيل المثال، إذا كان المورد "Users"، فاستدعِgetUsers) مع تمرير القيمة كوسيط (argument). - استدعِ
getProductsمع وسيطين:"electronics"و"active". - استدعِ الطريقة الثابتة
createOrderمع تمرير القيمة كوسيط. - استدعِ الطريقة الثابتة
deleteItemمع تمرير معرف المورد كوسيط.
- استدعِ طريقة
تسمح الطرق السحرية لعميل API الخاص بك بالاستجابة لأي استدعاء طريقة بشكل ديناميكي. بدلاً من تحديد getUsers() و getPosts() و getProducts() وعشرات غيرها، تتعامل طريقة __call() واحدة معها جميعاً من خلال فحص اسم الطريقة واستخراج المعلومات ذات الصلة.
ورقة مرجعية
تعترض الطريقة __call() استدعاءات طرق النسخة (instance methods) التي لا توجد أو لا يمكن الوصول إليها. وهي تستقبل اسم الطريقة ومصفوفة من الوسائط:
<?php
class Messenger {
public function __call(string $name, array $arguments): string {
return "Called '$name' with: " . implode(", ", $arguments);
}
}
$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");
// المخرجات: Called 'sendEmail' with: Hello, World
تعترض الطريقة __callStatic() استدعاءات الطرق الساكنة (static methods). ويجب التصريح عنها كـ static:
<?php
class QueryBuilder {
public static function __callStatic(string $name, array $arguments): string {
if (str_starts_with($name, "findBy")) {
$field = substr($name, 6);
return "Finding by $field: " . $arguments[0];
}
return "Unknown method: $name";
}
}
echo QueryBuilder::findByEmail("test@example.com");
// المخرجات: Finding by Email: test@example.com
هذه الطرق السحرية (magic methods) مفيدة لإنشاء واجهات برمجة تطبيقات سلسة (fluent APIs)، أو تنفيذ إعادة توجيه الطرق (method forwarding)، أو بناء منشئي استعلامات ديناميكيين حيث تترجم أسماء الطرق إلى عمليات.
جرّب بنفسك
<?php
require_once 'ApiClient.php';
// قراءة المدخلات
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: إنشاء مثيل من ApiClient باستخدام عنوان URL الأساسي
// TODO: استدعاء طريقة get ديناميكية باستخدام المورد كلاحقة لاسم الطريقة
// تلميح: استخدم استدعاءات الطرق المتغيرة مثل $api->{"get" . $resource}($value)
// TODO: استدعاء getProducts مع وسيطين: "electronics" و "active"
// TODO: استدعاء الطريقة الثابتة createOrder مع القيمة كوسيط
// تلميح: استخدم ApiClient::createOrder($value)
// TODO: استدعاء الطريقة الثابتة deleteItem مع المورد كوسيط
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsالكلمة المفتاحية $thisالـ Methodsالـ Propertiesالمنشئ (__construct)الهادم (__destruct)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةالكلمة المفتاحية parent::إعادة تعريف الدوال (Method Overriding)الكلمة المفتاحية finalالأصناف المجردة (Abstract Classes)مراجعة - هيكلية الموظفين7التغليف (Encapsulation)
العام، المحمي، الخاص (Public, Protected, Private)نظرة متعمقة على معدلات الوصولدوال Getters و Settersإخفاء المعلوماتميزة Constructor Promotion (8.0)مراجعة - نظام سجلات الطلاب10مفاهيم البرمجة كائنية التوجه المتقدمة
التركيب مقابل الوراثةحقن التبعيةالأصناف المجهولةالتعدادات (PHP 8.1)الألياف (PHP 8.1)تعمق في استنساخ الكائناتالمولدات والمكررات13أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع2مساحات الأسماء والتحميل التلقائي
مقدمة إلى مساحات الأسماءالكلمة المفتاحية useمعيار التحميل التلقائي PSR-4أداة التحميل التلقائي Composerملخص - مشروع منظم5الواجهات والعقود
مقدمة إلى الواجهاتتنفيذ الواجهاتتنفيذ واجهات متعددةالواجهة مقابل الـ Abstract Classالـ Type Hinting مع الواجهاتملخص - حاسبة الأشكال8الميثودات السحرية (Magic Methods)
مقدمة في الميثودات السحرية__toString و __debugInfo__get, __set, __isset, __unset__call و __callStatic__clone واستنساخ الكائنات__serialize و __unserializeمراجعة - Custom Collection3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)