Existem diversas formas de estruturar o código e o projeto da sua aplicação web e você pode gastar muito ou pouco esforço pensando na sua arquitetura. Mas geralmente é uma boa ideia seguir à padrões comuns, pois isso irá fazer com que seu código seja mais fácil de manter e de ser entendido por outros desenvolvedores.
Um dos padrões de design mais utilizados é o padrão “Factory” (Fábrica). Através dele uma classe simplesmente cria o objeto que você gostaria de usar. Considere o seguinte exemplo desse padrão de design:
Esse código usa uma “Factory” para criar o objeto do tipo “Automobile”. Existem dois possíveis benefícios para criar seu código dessa forma, o primeiro é que se você precisar mudar, renomear ou substituir a classe Automobile futuramente você pode fazer e só terá que modificar o código na “Factory”, em vez de em todos os lugares do seu projeto onde você usa a classe Automobile. O segundo benefício possível é que caso a criação do objeto seja um processo complicado, você pode executar todo esse trabalho na factory, em vez de repetí-lo toda vez que precisar criar uma nova instância da classe.
Usar o padrão de “Factory” não é sempre necessário (ou esperto). O código de exemplo usado aqui é tão simples que essa “Factory” estaria simplesmente adicionando complexidade indesejada. Entretanto se você estiver realizando um projeto um pouco maior ou mais complexo você pode se salvar de muitos problemas com o uso do padrão “Factory”.
Quando arquitetando uma aplicação web, é comum fazer sentido tanto conceitualmente quanto arquitetonicamente permitir o acesso a somente uma instância de uma classe em particular, o padrão “Singleton” nos permite realizar essa tarefa.
O código acima implementa o padrão “Singleton” usando uma variável estática
e o método estático de criação getInstance()
.
Note o seguinte:
__construct
é declarado como protegido para prevenir que uma nova instância seja criada fora dessa classe pelo operador new
.__clone
é declarado como privado para prevenir a clonagem dessa instância da classe pelo operador clone
.__wakeup
é declarado como privado para prevenir a desserialização de uma instância dessa classe pela função global unserialize()
.getInstance()
declarado como estático. Isso permite a criação de classes “filhas” da classe Singleton no exemploO padrão Singleton é útil quando você precisa garantir que somente uma instância da classe seja criada em todo o ciclo de vida da requisição em uma aplicação web. Isso tipicamente ocorre quando você tem objetos globais (tais como uma classe de Configuração) ou um recurso compartilhado (como uma lista de eventos).
Você deve ser cauteloso quando for usar o padrão “Singleton” já que pela sua própria natureza ele introduz um estado global na sua aplicação reduzindo a possibilidade de realização de testes. Na maioria dos casos Injeção de Dependências pode (e deve) ser usado no lugar de uma classe do tipo Singleton. Usar Injeção de Dependências significa não introduzir acoplamento desnecessário no design da sua aplicação, já que o objeto usando o recurso global ou compartilhado não necessita de conhecimento sobre uma classe concretamente definida.
Com o padrão “Strategy” (Estratégia) voce encapsula famílias específicas de algoritimos permitindo com que a classe cliente responsável por instanciar esse algoritimo em particular não necessite de conhecimento sobre sua implementação atual. Existem várias variações do padrão “Strategy” o mais simples deles é apresentado abaixo:
O primeiro bloco de código apresenta uma familia de algorítimos; você pode querer uma array serializado, um JSON ou talvez somente um array de dados:
Através do encapsulamento do algoritimo acima você está fazendo seu código de forma limpa e clara para que outros desenvolvedores possam facilmente adicionar novos tipos de saída sem que isso afete o código cliente.
Você pode ver como cada classe concreta ‘output’ implementa a OutputInterface - isso serve a dois propósitos, primeiramente isso prevê um simples contrato que precisa ser obedecido por cada implementação concreta. Segundo, através da implementação de uma interface comum você verá na próxima seção que você pode utilizar Indução de Tipo para garantir que o cliente que está utilizando esse comportamento é do tipo correto, nesse caso ‘OutputInterface’.
O próximo bloco de código demonstra como uma classe cliente relizando uma chamada deve usar um desses algorítimos e ainda melhor definir o comportamento necessário em tempo de execução:
A classe cliente tem uma propriedade private que deve ser definida em tempo de execução e ser do tipo ‘OutputInterface’ uma vez que essa propriedade é definida uma chamada a loadOutput() irá chamar o método load() na classe concreta do tipo ‘output’ que foi definida.
O padrão front controller é quando você tem um único ponto de entrada para sua aplicação web (ex. index.php) que trata de todas as requisições. Esse código é responsável por carregar todas as dependências, processar a requisição e enviar a resposta para o navegador. O padrão Front Controller pode ser benéfico pois ele encoraja o desenvolvimento de um código modular e provê um ponto central no código para inserir funcionalidades que deverão ser executadas em todas as requisições (como para higienização de entradas).
O padrão model-view-controller (MVC) e os demais padrões relacionados como HMVC and MVVM permitem que você separe o código em diferentes objetos lógicos que servem para tarefas bastante específicas. Models (Modelos) servem como uma camada de acesso aos dados onde esses dados são requisitados e retornados em formatos nos quais possam ser usados no decorrer de sua aplicação. Controllers (Controladores) tratam as requisições, processam os dados retornados dos Models e carregam as views (Visões) para enviar a resposta. E as views são templates de saída (marcação, xml, etc) que são enviadas como resposta ao navegador.
O MVC é o padrão arquitetônico mais comumente utilizado nos populares Frameworks PHP.
Leia mais sobre o padrão MVC e os demais padrões relacionados: