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;
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: Inicial Estado 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: Alterado Estado 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: Inicial Estado 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.

