修复设计模式-PHP中的Singleton

我最近写过关于如何打破设计模式-PHP中的Singleton的文章 。 写完本文之后,我正在寻找该模式的实现的新版本:有没有一种方法可以在PHP中创建Singleton,而又没有机会使用Closure::bind()创建类的新实例?


如何在PHP中修复Singleton


我提出了许多不同的选择,但也找到了解决这些问题的方法。 在我看来,不可能创建一个新的实现,但是一个想法来了,我开始测试它。


实际上,这里是代码和指向sandbox链接 。 让我们拆开它:


 <?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); // Fatal error: Class is already instantiated $newInstanceClosure(); 

我们将静态变量$instance转移到getInstance()方法,以便我们无法使用匿名函数中的selfstatic运算符访问它。


在类构造函数中,我们还添加了一个存储布尔值的静态变量。 创建新对象时,我们检查此变量的值:如果在其中存储了false ,则将该变量设置为true并成功创建对象。 尝试创建新对象时,代码将陷入if ,因为在创建第一个对象时,我们将静态变量$hasInstance写入true ,然后在$hasInstance ,将导致用户错误, Class is already instantiatedClass is already instantiated文本。


在魔术方法__clone()__wakeup()我们还导致用户错误和相应的消息,以致无法使用匿名运算符中的clone运算符和序列化机制创建对象。


如果需要,可以引发异常而不是用户错误。


因此,可以仅创建该类的一个Singleton对象。 到目前为止,我还没有找到打破这种模式实现的方法,因此,如果有人可以做到,请在注释中写出:)


感谢您的关注!

Source: https://habr.com/ru/post/zh-CN450626/


All Articles