Eu escrevi recentemente sobre como quebrar o padrão de design - Singleton em PHP . Após escrever o artigo, eu estava procurando uma nova versão da implementação do padrão: existe uma maneira de criar Singleton no PHP sem dar a oportunidade de criar novas instâncias da classe usando Closure::bind()
?

Eu vim com muitas opções diferentes, mas também encontrei maneiras de contorná-las. Já me pareceu que não seria possível criar uma nova implementação, mas surgiu uma ideia e comecei a testá-la.
Aqui, de fato, o código e o link para a sandbox . Vamos desmontar:
<?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 a variável estática $instance
para o método getInstance()
para que não possamos acessá-la usando os operadores self
e static
na função anônima.
No construtor da classe, também adicionamos uma variável estática que armazena um valor booleano. Ao criar um novo objeto, verificamos o valor dessa variável: se false
for armazenado lá, definiremos essa variável como true
e o objeto será criado com êxito. Ao tentar criar um novo objeto, o código entrará em if
, pois ao criar o primeiro objeto, escrevemos true
para a variável estática $hasInstance
, depois no corpo if
', e causaremos um erro do usuário com o texto Class is already instantiated
.
Nos métodos mágicos __clone()
e __wakeup()
também causamos erros no usuário com as mensagens correspondentes para não podermos criar objetos usando o operador clone
e o mecanismo de serialização em uma função anônima.
Se desejar, você pode lançar exceções em vez de erros do usuário.
Assim, é possível criar apenas um objeto Singleton da classe. Até agora, não encontrei uma maneira de quebrar essa implementação do padrão; portanto, se alguém puder fazê-lo, escreva sobre isso no comentário :)
Obrigado pela atenção!