Corrigir padrão de design - Singleton em PHP

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() ?


Como corrigir Singleton em PHP


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

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!

Source: https://habr.com/ru/post/pt450626/


All Articles