Recientemente escribí sobre cómo romper el patrón de diseño: Singleton en PHP . Después de escribir el artículo, estaba buscando una nueva versión de la implementación del patrón: ¿hay alguna forma de crear Singleton en PHP sin dar la oportunidad de crear nuevas instancias de la clase usando Closure::bind()
?

Se me ocurrieron muchas opciones diferentes, pero también encontré formas de sortearlas. Me pareció que no sería posible crear una nueva implementación, pero surgió una idea y comencé a probarla.
Aquí, de hecho, el código y el enlace al sandbox . Vamos a desarmarlo:
<?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);
transferimos la variable estática $instance
al método getInstance()
para que no podamos acceder a ella utilizando los operadores self
y static
en la función anónima.
En el constructor de la clase, también agregamos una variable estática que almacena un valor booleano. Al crear un nuevo objeto, verificamos el valor de esta variable: si false
se almacena allí, establecemos esta variable en true
y el objeto se crea con éxito. Cuando intente crear un nuevo objeto, el código caerá en if
, ya que al crear el primer objeto escribimos true
a la variable estática $hasInstance
, luego en el cuerpo if
', y provocaremos un error de usuario con el texto Class is already instantiated
.
En los métodos mágicos __clone()
y __wakeup()
también __wakeup()
errores de usuario con los mensajes correspondientes para no poder crear objetos usando el operador de clone
y el mecanismo de serialización en una función anónima.
Si lo desea, puede lanzar excepciones en lugar de errores de usuario.
Por lo tanto, es posible crear solo un objeto Singleton de la clase. Hasta ahora no he encontrado una manera de romper esta implementación del patrón, así que si alguien puede hacerlo, escribe sobre eso en el comentario :)
Gracias por su atencion!