كتبت مؤخرًا حول كيفية كسر نمط التصميم - Singleton في PHP . بعد كتابة المقالة ، كنت أبحث عن إصدار جديد من تنفيذ النموذج: هل هناك طريقة لإنشاء Singleton في PHP دون إعطاء الفرصة لإنشاء مثيلات جديدة من الفصل باستخدام Closure::bind()
؟

توصلت إلى العديد من الخيارات المختلفة ، لكنني وجدت أيضًا طرقًا للتغلب عليها. بدا لي بالفعل أنه لن يكون من الممكن إنشاء تطبيق جديد ، لكن الفكرة جاءت وبدأت في اختباره.
هنا ، في الواقع ، رمز وصلة إلى رمل . لنفصلها:
<?php final class Singleton { public static function getInstance() { static $instance; if (null === $instance) { $instance = new self(); } return $instance; } private function __construct() { static $hasInstance = false; if ($hasInstance) { \trigger_error('Class is already instantiated', \E_USER_ERROR); } $hasInstance = true; } private function __clone() { \trigger_error('Class could not be cloned', \E_USER_ERROR); } private function __wakeup() { \trigger_error('Class could not be deserialized', \E_USER_ERROR); } } $s1 = Singleton::getInstance(); \var_dump(\spl_object_id($s1)); $createNewInstance = function () { return new self(); }; $newInstanceClosure = Closure::bind($createNewInstance, $s1, Singleton::class);
نقوم بنقل المتغير static $instance
إلى أسلوب getInstance()
حتى لا يمكننا الوصول إليه باستخدام العوامل self
static
في الوظيفة المجهولة.
في مُنشئ الفصل الدراسي ، نضيف أيضًا متغيرًا ثابتًا يخزن قيمة منطقية. عند إنشاء كائن جديد ، نتحقق من قيمة هذا المتغير: إذا تم تخزين false
هناك ، فسنقوم بتعيين هذا المتغير على true
ويتم إنشاء الكائن بنجاح. عند محاولة إنشاء كائن جديد ، $hasInstance
الشفرة في if
، لأنه عند إنشاء الكائن الأول كتبنا true
للمتغير الثابت $hasInstance
، ثم في $hasInstance
، $hasInstance
في حدوث خطأ مستخدم في النص Class is already instantiated
.
في الطرق السحرية __clone()
و __wakeup()
أيضًا في أخطاء المستخدم مع الرسائل المقابلة حتى لا نتمكن من إنشاء كائنات باستخدام عامل clone
وآلية التسلسل في وظيفة مجهولة.
إذا رغبت في ذلك ، يمكنك رمي استثناءات بدلاً من أخطاء المستخدم.
وبالتالي ، من الممكن إنشاء كائن Singleton واحد فقط من الفصل الدراسي. حتى الآن ، لم أجد طريقة لكسر هذا التطبيق للنمط ، لذلك إذا كان بإمكان شخص ما فعل ذلك ، فاكتب عنه في التعليق :)
شكرا لاهتمامكم!