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.
Olá Felipe,
Fico feliz que tenha gostado do que escrevi. Também lhe dou os parabéns pela qualidade de seus artigos.
Concordo plenamente com o que você falou sobre a inexistência da aplicação em PHP, o que em tese, inviabilizaria o Singleton. O que fiz foi uma adaptação para resolver um caso específico.
Com relação ao uso das sessions diretamente na classe de negócio, esta é uma questão controversa. Se estivéssemos falando de Java, eu provavelmente estaria equivocado, afinal, mesmo que eu jamais desenvolvesse aplicativos que não fossem voltados à web, ainda sim, estaria ferindo o MVC, uma vez que traria elementos particulares deste ambiente ao modelo da aplicação. Se um dia quisesse portar minha aplicação para um desktop, por exemplo, teria que mexer no modelo.
No caso do PHP, convenhamos, a Web é a finalidade de 99% das aplicações. Achei interessante o que disse Jason E. Sweat, em seu livro Guide to PHP Design Patterns.
“There seems to be a number of “what goes where” questions surrounding MVC, and you can receive
substantially different answers from different MVC proponents.
Where does $_SESSION belong? One argument says that sessions are a persistent data store, usually
implemented as files on the server and are therefore best kept in the Model. A second set of
developers argues that like the other PHP superglobals, session data is an input to the system and
therefore belongs in the Controller. Yet another set of developers say sessions are implemented using
cookies, a technology that only works with HTML over HTTP and therefore sessions are View related.”
Em suma, em Java eu diria que Sessions deveriam ser manipuladas pelo Controlador, sob pena de acontecer o que já citei, no entanto, em PHP, não acredito que tenha tantos problemas.
Sei lá… Talvez eu é que tenha falado besteira, mas tudo bem.
Ahh, coloquei um link pro seu blog no meu também.
Grande Abraço.
Cara ótimo artigo bixo! PQP como eu queria que vc fizesse parte do imasters. Isso é mto esclarecedor para qm acha q os frameworks implementam o singleton. Velhpo se puder entrar em contato cmg tenho um projeto interessante sobre design patterns em php. Na real para um livro.
jnascimento@gmail.com