Desmistificando o Singleton no PHP
Posted: January 16th, 2007 | Author: Felipe Ribeiro | Filed under: Uncategorized | Tags: design patterns, php | 1 Comment »Ontem eu sugeri dois livros sobre Design Patterns, e hoje eu vou entrar em alguns detalhes do padrão Singleton e como ele se comporta no PHP.
Por definição, o padrão Singleton serve para garantir que exista apenas uma instância de determinada classe e mantendo um ponto global de acesso à essa instância. Por exemplo, eu desejo que na minha aplicação exista uma entidade responsável por gerar logs, e ela precisa ser única pois acessos concorrentes a um arquivo podem ser desastrosos, ou eu tenho limitações de recurso e preciso de uma entidade única que gerencie uma conexão socket ou com um banco de dados. E para isso foi formalizado o padrão Singleton.
Para garantir que só existe uma instância daquela classe eu preciso me preocupar em tratar a criação desse objeto, ou seja, limitar essa criação fazendo com que o sistema antes de criar, cheque se já existe uma instância, caso positivo retorna essa instância, caso contrário cria uma nova. Para isso, eu preciso fazer com que meu construtor seja *privado*, sendo assim acessado só por métodos da mesma classe, e prover um método de classe (estático) que possa checar a existência prévia da instância. Em PHP a implementação seria assim:
<?class XPTO {private static $instance;private $estado; //Usaremos esse campo mais na frente
public static function getInstance() { if(empty(self::$instance)) { self::$instance = new XPTO(); } return self::$instance;}
private function __construct() { $this->setEstado("Inicial"); }
public function getEstado() { return $this->estado;}
public function setEstado($novoEstado) { $this->estado = $novoEstado;}}?>
Sendo assim, eu não posso, de fora da classe, instanciar um novo objeto do tipo XPTO, mas tenho que chamar o metodo getInstance para pegar a instancia única dessa classe.
Até aqui tudo parece muito bonito, mas aí esbarramos numa limitação do PHP nesse sentido: Em PHP não existe o conceito de Aplicação, ou seja, cada vez que alguem acessa sua página, o que acontece é apenas a execução de um script numa thread do seu webserver, e mesmo que várias pessoas acessam simultaneamente o *mesmo* script, essas execuções são independentes, não há relação nenhuma entre elas. E como não existe o conceito de aplicação, os objetos e variáveis só permanecem na memória no curto tempo da execução do script, quando o PHP processa o script e devolve ao webserver para ser enviado para o visitante, aqueles valores utilizados são limpados da memória.
Seguindo esse raciocínio chegamos a conclusão de que em PHP o padrão Singleton é útil para organizar as idéias do programador e deixar o código melhor organizado evitando variáveis globais, porém não provê todas as funcionalidades que se espera dele, e para demonstrar essa conclusão executarei o seguinte teste:
1 – Crio o arquivo teste.php.
2 – Nesse arquivo importo a classe XPTO criada anteriormente:
<? require("Xpto.class.php"); ?>
3 – Pego a instância única da classe XPTO e checo qual o estado atual dele:
<?$xpto = XPTO::getInstance();print("Estado atual do objeto XPTO: " . $xpto->getEstado());?>
4 – Pego novamente a instância, altero esse estado e checo novamente:
<?$xpto = XPTO::getInstance();$xpto->setEstado("Alterado");print("<br/>Estado atual do objeto XPTO (depois de alterado): " . $xpto->getEstado());?>
Quando esse script for executado, pela primeira vez, a saída será:
Estado atual do objeto XPTO: InicialEstado atual do objeto XPTO (depois de alterado): Alterado
Se houvesse o conceito de aplicação, esse objeto persistiria na memória e na próxima execução a saída *seria*:
Estado atual do objeto XPTO: AlteradoEstado atual do objeto XPTO (depois de alterado): Alterado
Mas quando o PHP terminou de processar a primeira execução, ele removeu tal objeto da memória e na segunda execução ele foi recriado do zero, voltando ao estado inicial e tendo a saída idêntica à primeira execução.
Estado atual do objeto XPTO: InicialEstado atual do objeto XPTO (depois de alterado): Alterado
Existem outras maneiras de se testar isso, mas essa foi a maneira que achei mais simples.
E esses foram meus dois centavos para mostrar que o Singleton em PHP nem sempre funciona como pensamos.














