Fork me on GitHub

Grupo de desenvolvedores de PHP do estado de São Paulo
Próximos encontros e eventos? Visite a página do PHPSP no Meetup

AOP: Programação Orientada a Aspectos com Go! Aop

Por em em Artigos

AOP: Programação Orientada a Aspectos com Go! Aop

AOP é um paradigma de programação utilizado para diminuir o acoplamento de códigos de interesse compartilhado. Muitos dicionários definem Apecto como aparência ou face exterior. Em programação, Aspecto é aquele código que não está relacionado a um objetos em si, mas seu comportamento é compartilhado por diversos objetos da aplicação, ou seja, faz parte da aparência da aplicação e é de interesse compartilhado. Um bom exemplo disso é a autorização em sistemas. Toda vez que um recurso da aplicação é acessado, é necessário verificar se o usuário que está acessando tem autorização para acessá-lo. Mesmo se isolarmos o código de autorização, ele precisará ser executado a todo momento em que for necessário fazer esta verificação. Outro exemplo é o controle transacional em repositórios que acessam bancos de dados. Os métodos que gravam dados no banco (insert, update ou delete) muitas veze precisam ser executados dentro de uma transação. Ou seja, iniciar uma transação e efetivar a gravação dos dados no banco é um comportamento de interesse compartilhado entre a classes de repositório. Nós veremos como separar este comportamento de interesse compartilhado com AOP utilizando o framework Go! Aop.

Trabalhando com o Go! Aop

Para conseguirmos trabalhar com o Go! Aop, devemos entender como podemos dizer que uma parte do sistema possui um determinado aspecto e em que momento o aspecto irá trabalhar. Para isso, usamos Pointcuts e Advices. Para saber mais, acesse a sessão documentação completa sobre pointcuts e advices.

Pointcuts

Os Pointcuts informam quem são os alvos, ou seja, em que métodos do sistema o comportamento do aspecto será executado. Para isso, devemos informar se será aplicado em método publico ou privado, seguido da classe, do método e seus argumentos. Veja o exemplo a seguir:

Podemos também utilizar o caracter * como coringa, o que nos permitirá aplicar o aspecto em diversas classes e diversos métodos. Aqui é onde as coisas ficam legais, pois é dessa forma que criamos um aspecto de fato na aplicação.

Advices

Os Advices determinam em que momento da execução do método alvo o aspecto será invocado. O Go! Aop nos permite fazer isso através de annotations. São elas: @Before, @After, @AfterThrowing e @Around.

  • @Before: O comportamento do aspecto será executado antes do método alvo
  • @After: O comportamento do aspecto será executado depois do método alvo
  • @AfterThrowing: O comportamento do aspecto será executado somente se o método alvo lançar alguma exceção
  • @Around: O comportamento do aspecto será executado antes e depois do método alvo

Exemplos

Exemplo 1 – Antes de qualquer método público da classe Aspecto\Controller\ContatoController com qualquer parâmetro

Exemplo 2 – Depois de qualquer método público de qualquer classe que estiver dentro do pacote Aspecto\Controller e terminar com Controller

Exemplo 3 – Antes e depois de qualquer método da aplicação

Instalando e configurando o Go! Aop

Crie uma pasta chamada PHPAspect e dentro dela e crie um arquivo composer.json com o seguinte conteúdo:

Após isso, rode o comando composer install para instalar as dependências. Crie também uma pasta na raiz do projeto chamada src e dentro dela crie um arquivo chamado ApplicationAspectKernel.php. É este arquivo que conterá a classe responsável por integrar os aspectos à nossa aplicação. A nossa classe deve extender de Go\Core\AspectKernel e implementa o método configureAop, que nos permitirá registrar os aspectos.

Após isso, iremos inicializar o framework no bootstrap da nossa aplicação. Crie um arquivo chamado index.php na raiz do projeto com o seguinte conteúdo:

Vamos criar duas classes para demonstrar o funcionamento do aspecto, chamadas ClasseA e ClasseB. Elas terão apenas o método executa() e não receberá nenhum parâmetro. Crie os arquivos ClasseA.php e ClaseB.php dentro de src:

Para criar nosso aspecto, devemos criar uma classe que implemente a interface Go\Aop\Aspect. A partir daí, é possível criar os métodos que serão invocados, e por meio de anotações, informar os pointcuts e advices.

Vamos criar nosso primeiro aspecto. Ele conterá a classe responsável imprimir o tempo total de execução de todos os métodos que forem executados. Como esse comportamento é de interesse compartilhado, ele será um aspecto da nossa aplicação. Dentro de src, crie um arquivo chamado ProfiladorAspect.php:

O método beforeMethodInvocation recebe a anotação @Before para que seja executado antes do nosso alvo, e public Aspect\*->(*) define que nosso alvo é qualquer método de qualquer classe que esteja dentro do pacote Aspect. O mesmo ocorre com o método afterMethodInvocation, a diferença é que este recebe a annotation @After, para que seja executado ao fim do método alvo, nos permitindo obter o tempo total de execução do método.

Após criado um aspecto, é necessário registrá-lo. Dessa forma, o Go! Aop passa a saber da sua existência, e pelas anotações identifica os advices e pointcuts do aspecto. Editaremos a classe Aspect\ApplicationAspectKernel e colocaremos uma linha dentro do método configureAop(), ficando então desta forma:

Registrado o nosso aspecto, vamos instanciar as classes Aspect\ClasseA e Aspect\ClasseB e executar seus métodos executa() dentro do arquivo index.php. Se tudo ocorrer bem, ao executar o método executa() de cada classe, os comportamentos contidos dentro do aspecto deverão ser invocados. Insira as linhas a seguir no final do arquivo index.php:

Com isso, basta executar o arquivo index.php que se encontra na raiz do projeto por linha de comando ou rodar um servidor php e veremos a saída do nosso profilador.

Linha de comando:

$ php index.php

Servidor:

$ php -sS localhost:8080

Deverá ser impresso a seguinte mensagem:

Vamos colocar uma chamada da função sleep() dentro dos métodos executa() para ver melhor o seu funcionamento. Insira a seguinte linha nos dois métodos executa():

Execute novamente o arquivo index.php para ver o novo resultado.

Note que em momento algum a as classes Aspect\ClasseA ou Aspect\ClasseB tiveram contato com o nosso aspecto. Dessa forma, podemos isolar comportamentos de log de sistema, autenticação e autorização, sistemas transacionais e boa parte da nossa infraestrutura. Um controlador, por exemplo, não precisa saber que ele atende requisições HTTP, podemos deixar a comunicação com HTTP por parte de um aspecto. Basta que os controladores retornem os resultados esperados. O mesmo acontece com gerenciador de rotas. Todos esses exemplos são comportamentos de interesse compartilhado da aplicação e podem ser isolados em aspectos.

Tags: , ,