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

我提出了许多不同的选择,但也找到了解决这些问题的方法。 在我看来,不可能创建一个新的实现,但是一个想法来了,我开始测试它。
实际上,这里是代码和指向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);
我们将静态变量$instance
转移到getInstance()
方法,以便我们无法使用匿名函数中的self
和static
运算符访问它。
在类构造函数中,我们还添加了一个存储布尔值的静态变量。 创建新对象时,我们检查此变量的值:如果在其中存储了false
,则将该变量设置为true
并成功创建对象。 尝试创建新对象时,代码将陷入if
,因为在创建第一个对象时,我们将静态变量$hasInstance
写入true
,然后在$hasInstance
,将导致用户错误, Class is already instantiated
了Class is already instantiated
文本。
在魔术方法__clone()
和__wakeup()
我们还导致用户错误和相应的消息,以致无法使用匿名运算符中的clone
运算符和序列化机制创建对象。
如果需要,可以引发异常而不是用户错误。
因此,可以仅创建该类的一个Singleton对象。 到目前为止,我还没有找到打破这种模式实现的方法,因此,如果有人可以做到,请在注释中写出:)
感谢您的关注!