PHP, Traits e Singleton
A minha maior motivação em participar do fórum iMasters, sempre foi ajudar, ensinar e aprender. O último, como sempre, é o maior ganho que se pode ter, aprender enquanto ajuda alguém com dificuldade. Dentro desse contexto, algumas situações acabam nos dando uma lição ainda mais surpreendente.
A partir de um questionamento (Qual a utilidade da traits), me vi intrigado em demonstrar exemplos práticos de quão poderosa as traits são. Além disso, como dizia tio Ben, “grandes poderes requerem grandes responsabilidades”.
Traits
O manual é bem claro quanto a motivação das traits:
Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity, and avoids the typical problems associated with multiple inheritance and Mixins.
Parafraseando e simplificando, traits
são um mecanismo de reutilização de código para linguagens de herança
simples/única. Dessa forma, é uma adição a herança tradicional habilitando a composição horizontal de
comportamento.
Uma trait
pode agrupar um conjunto de funcionalidades e estas serem introduzidas em outras classes ou objetos. Assim,
esta classes irão encorporar o comportamento da trait
, da mesma forma que se o código da trait
. Isso se dá devido
ao funcionamento do interpretador para com a trait
. Ele realmente copia e cola o código da trait
dentro da classe
em que ela foi definida.
Singleton
Singleton
é um padrão de projeto que define que uma classe deve possuir apenas uma instância
e um ponto de acesso global.
Normalmente, o padrão, é muito mal utilizado. Mas, sempre há a sua aplicabilidade. Um dos mais famosos uso é o
Registry
.
Registry
é um repositórios de objetos. Normalmente ele é aplicado como um padrão Singleton (mas não necessariamente
deve ser um).
Dessa forma, vamos a implementação de um Registry:
O Registry
, nesse exemplo, é um Singleton
. Os seguintes pontos são específicos do Singleton
:
__construct
:private
- não permitir criar uma instância diretamente;__wakeup
:private
- não permitir unserialize;__clone
:private
- não permitir o clone da instância;getInstance
:public
- retornar a instância única;$instance
:private
estatic
- manter, a nível de classe, a instância única.
Por outro lado, os demais métodos são específicos do Registry
:
get
: retornar um registro;set
: inserir um registro;has
: verificar se um registro existe.
Suponha que precise de outra classe que implemente o Singleton
(um manipulador para o DOM, por exemplo). Logo, eu
preciso implementar todos os métodos básicos novamente. Vamos ao molde da nossa próxima classe Singleton:
O código acima exemplifica o básico para uma classe Singleton
. Qualquer classe que necessitar ser um
Singleton
, deverá implementar o código acima.
Como é de praxe, sabe-se que copiar e colar não é uma boa alternativa e, nesse caso, devemos encontrar uma maneira para que o código seja reutilizado.
Outro ponto importante, é que uma classe Singleton
não atua muito bem com herança (na realidade, ela inibe o uso da
herança por trazer para si o controle da instância). Dessa forma, não é interessante implementar o Singleton
como uma
classe abstrata. Apesar de ser totalmente possível, apenas não é aconselhado.
Eis que surgem as traits
. Nesse caso, é possível separar em uma trait
, toda a implementação do Singleton
.
As únicas diferenças da implementação via trait
são: a adição da keyword final
, para a classe que implementar
o Singleton
não sobrescreva o método implementado, e a implementação do método init
, que pode ser usado como
construtor de uma classe.
Dessa forma, a classe Registry
pode ser reescrita da seguinte maneira:
Assim, foi utilizada uma trait
(que realiza o copy and paste) para evitar o “copia e cola” de códigos através de
vários arquivos.
De qualquer forma, esse é apenas um dos muitos exemplos da aplicabilidade de uma trait, algumas das quais irei trazer em breve.