في يوم عمل جيد ، كتبت اختبارات وحدة لمنطق العمل في المشروع الذي أعمل فيه. كانت مهمتي هي تهيئة بعض الخصائص الخاصة للفصل بقيم محددة.
لا يمكن استخدام المستوطنين العاديين ، حيث تم توضيح بعض المنطق هناك. لم ينجح وراثة الفصل أو حبسه ، لأنه تم إعلانه نهائيًا. وحتى التفكير لم يصلح. لذلك بدأت أبحث عن حلول لهذه المشكلة.
لقد وجدت مقالًا مثيرًا للاهتمام يصف كيف يمكن تأمين الفصل النهائي باستخدام مكتبة dg / الالتفافية النهائية . أعجبني هذا الخيار وحاولت تنفيذه. لسوء الحظ ، لم تنجح ، لأن المشروع يستخدم الإصدار القديم من PHPUnit.
عند الانعكاس ، تذكرت فئة Closure
، وتحديداً حول طريقة bind()
الثابتة bind()
، والتي يمكنها تنفيذ وظائف مجهولة في سياق الكائن المطلوب للفصل الدراسي. يمكن الاطلاع على مزيد من المعلومات حول هذا في الوثائق الرسمية . لذلك ، قمت بإنشاء سمة استخدمتها في اختباراتي (ربما يكون شخص ما مفيدًا أيضًا)
trait PrivatePropertySetterTrait { protected function assignValue($object, string $attribute, $value) { $setter = function ($value) use ($attribute) { $this->$attribute = $value; }; $setterClosure = \Closure::bind($setter, $object, \get_class($object)); $setterClosure($value); } }
تأخذ هذه السمة كائن فئة ، واسم الخاصية التي تريد تعيين القيمة لها ، وفي الواقع ، القيمة نفسها. بعد ذلك ، يتم الإعلان عن وظيفة مجهولة المصدر بسيطة ، والتي باستخدام $this
المؤشر $this
، يعين القيمة الناتجة إلى خاصية فئة. بعد ذلك ، تأتي فئة Closure
مع طريقة bind()
الثابتة bind()
. تقبل الطريقة كائن فئة والدالة المجهولة الموصوفة أعلاه والاسم الكامل للفئة. وبالتالي ، يتم تضمين وظيفة مجهولة في سياق الكائن وتعيد إلينا طريقة bind()
كائنًا من فئة Closure
، والذي يمكننا أن نسميه كدالة عادية ، لأنه يعرّف طريقة __invoke()
السحرية. وفويلا!
في النهاية ، تمكنت من حل مشكلتي ، ثم تذكرت نمط تصميم Singleton. هل سيكون من الممكن بنفس الطريقة تنفيذ وظيفة مجهولة من شأنها إنشاء كائنات جديدة من الفصل؟ بالطبع ذهبت للتحقق من ذلك!
عن طريق كتابة قطعة صغيرة من التعليمات البرمجية
رمل مع رمز
<?php final class Singleton { private static $instance; public static function getInstance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { } private function __clone() { } private function __wakeup() { } } $s1 = Singleton::getInstance(); \var_dump(\spl_object_id($s1)); $createNewInstance = function () { return new self(); }; $newInstanceClosure = Closure::bind($createNewInstance, $s1, Singleton::class); $s2 = $newInstanceClosure(); \var_dump(\spl_object_id($s2));
الذي يعمل على نفس المبدأ ، ولكن بدلاً من تعيين قيمة إلى خاصية فئة ، يتم إنشاء كائن جديد باستخدام عامل التشغيل new
. ترجع الدالة \spl_object_id()
معرف فريد للكائن. يمكن العثور على مزيد من المعلومات حول هذه الميزة في الوثائق . باستخدام spl_object_id()
و var_dump()
معرفات فريدة للكائنات وأرى أنها مختلفة! ما زلت تمكنت من تأكيد هذه النظرية وخلق مثيل جديد من فئة سينجلتون!
في هذه المقالة ، أردت مشاركة اكتشافاتي الغريبة مع مجتمع PHP.
شكرا لاهتمامكم!