2 de julho de 2012

Singletons

''Se o singleton fosse um meme ele seria o Forever Alone.'' 


Forever Alone é um meme que representa o nível extremo de solidão de uma pessoa. O Singleton é um Padrão de Projeto de Software (do inglês Design Patternque restringe a instanciação de uma classe a apenas um único objeto. Como podemos observar o comportamento do Singleton é semelhante ao de nosso amigo Forever Alone, ou seja, por mais que deseje, ele não vai encontrar ninguém de seu tipo (classe) para consolá-lo na solidão e terá que chorar as pitangas sozinho.

Deixando um pouco o blablablá envolvendo Singletons, Padrões de Projetos e memes a seguir estão 2 exemplos de implementação de uma classe Singleton em PHP, sendo que apenas a primeira implementação está correta. Para cada uma das implementações são realizados alguns testes básicos para validar (ou invalidar) a implementação.  


Implementação correta: definindo um objeto estático para a classe e deixar o construtor e o método clone como privados.

1:  <?php   
2:  class ForeverAlone{  
3:       /**Instância única*/  
4:       private static $instancia = null;  
5:       /**Quantidade de chamadas ao construtor*/  
6:       private static $chamadas_construtor = 0;  
7:       /**Quantidade de chamadas ao método getInstance()*/  
8:       private static $chamadas_instancia = 0;  
9:       private function __construct(){  
10:            // construtor privado  
11:            self::$chamadas_construtor;  
12:       }  
13:       private function __clone(){  
14:            // clone privado   
15:       }  
16:       public static function getInstance(){  
17:            self::$chamadas_instancia++;  
18:            if(self::$instancia == null){  
19:                 self::$instancia = new self();  
20:            }  
21:            return self::$instancia;  
22:       }  
23:       public function getStats(){  
24:            return 'Chamadas ao Construtor: ' . self::$chamadas_construtor . "\n" .   
25:            'Chamadas ao getInstance(): ' . self::$chamadas_instancia . "\n";  
26:       }  
27:  }  



Implementação errada: deixando o construtor e o método clone como public (ou esquecendo de implementar eles).


1:  <?php   
2:  class ForeverAlone{  
3:       /**Instância única*/  
4:       private static $instancia = null;  
5:       /**Quantidade de chamadas ao construtor*/  
6:       private static $chamadas_construtor = 0;  
7:       /**Quantidade de chamadas ao método getInstance()*/  
8:       private static $chamadas_instancia = 0;  
9:       public function __construct(){  
10:            // construtor privado  
11:            self::$chamadas_construtor;  
12:       }  
13:       public function __clone(){  
14:            // clone privado   
15:       }  
16:       public static function getInstance(){  
17:            self::$chamadas_instancia++;  
18:            if(self::$instancia == null){  
19:                 self::$instancia = new self();  
20:            }  
21:            return self::$instancia;  
22:       }  
23:       public function getStats(){  
24:            return 'Chamadas ao Construtor: ' . self::$chamadas_construtor . "\n" .   
25:            'Chamadas ao getInstance(): ' . self::$chamadas_instancia . "\n";  
26:       }  
27:  }  


Testes


1:  <?php  
2:  include('ForeverAlone.php');  
3:  $objeto1 = ForeverAlone::getInstance();  
4:  // Imprimindo as estatísticas  
5:  echo $objeto1->getStats();  
6:  // Nova chamada ao getInstance  
7:  $objeto2 = ForeverAlone::getInstance();  
8:  echo $objeto2->getStats();  
9:  // Chamada ao construtor  
10:  $objeto3 = new ForeverAlone(); // Na implementação correta gera erro, pois o método é privado  
11:  echo $objeto3->getStats();  
12:  // Chamada ao clone  
13:  $objeto4 = clone $objeto1;  // Na implementação correta gera erro, pois o método é privado
14:  echo $objeto4->getStats();  
15:  ?>