Programação PHP orientada a aspectos

Olá pessoal!

Este mês, concluímos o primeiro conjunto do curso de desenvolvedor PHP de back-end e os contratamos com poder e main (o máximo possível durante os feriados). O curso foi reabastecido com outro professor - Evgeny Volosatov , que muitos provavelmente conhecem. Bem, tradicionalmente compartilhamos coisas interessantes.

Vamos lá

Em qualquer aplicativo, há partes do código que cruzam várias partes da arquitetura ao mesmo tempo.

Esse problema não é tão óbvio ao trabalhar com uma estrutura totalmente funcional. Muito provavelmente, o seu problema será generalizado e haverá uma chance de que a estrutura já o tenha resolvido sacrificando uma divisão de responsabilidades ou fornecendo uma abstração sobre a estrutura. Muitas estruturas usam uma arquitetura orientada a eventos para resolver problemas de funcionalidade de ponta a ponta. Mas sempre chega um momento em que a estrutura não é capaz de fornecer o nível de controle desejado sobre uma parte específica da lógica. Isto é especialmente verdade ao usar microframes ou desenvolvimento com bibliotecas especializadas. Quanto mais seu aplicativo levar em conta os princípios de separação de responsabilidades, maior será o papel da funcionalidade de ponta a ponta em sua arquitetura.



Programação PHP orientada a aspectos


A Aspect Oriented Programming (AOP) é ​​um paradigma de programação focado na organização e modularização da funcionalidade de ponta a ponta. Casos de aplicativos - ACLs, log, manipulação de erros, armazenamento em cache.

As suposições internas (internas) do PHP (quando você define uma função / constante / classe, ela permanece definida para sempre) tornam o paradigma da AOP difícil de implementar.

O Li3 foi o primeiro a resolver o problema da funcionalidade de ponta a ponta usando um mecanismo de filtragem que permite filtrar a lógica de um método por meio de fechamentos. Para tornar o método filtrável, a implementação do Li3 requer a adição manual de código de modelo. Com essas limitações, as técnicas de AOP são limitadas às técnicas de filtragem.

Outras implementações conhecidas de AOP no PHP:


A extensão PECL AOP é uma abordagem interessante, mas ao mesmo tempo arriscada, pois o suporte a extensões PECL não é comum. Outra opção são as bibliotecas Go!, Que são uma implementação de AOP que corrige o código PHP em tempo real, o que possibilita o uso de métodos de AOP.

Existem outras implementações, mas a maioria delas é criada com base em proxies (tanto quanto eu sei), e essa abordagem tem muitas limitações.

Cara novo na área


A geração automática de código existe há muito tempo em PHP e é usada em muitas bibliotecas, por exemplo, ProxyManager. E, graças à adoção do Composer, Go! mostra que é possível editar o código rapidamente.

Se a geração de código ainda pode ser considerada simples, a correção do código é um pouco mais complicada. Primeiramente, no PHP não há analisador de código interno e, em segundo lugar, existem muito poucas bibliotecas que resolvem os problemas de análise do código PHP. O mais famoso é a biblioteca PHP-Parser . O Analisador de PHP é uma ótima ferramenta, mas até ignora a formatação de espaços nas árvores de sintaxe abstrata geradas. O que dificulta a correção do código. De fato, o código que precisa ser corrigido é um código executável real. Portanto, se você deseja que o retorno seja preciso com erros, considere os números de linha no arquivo corrigido.

Para esta tarefa, usamos o patcher de código Kahlan JIT. Kahlan é a nova estrutura de teste Unit & BDD, graças às técnicas de edição JIT que permitem código de patch de stub e monkey diretamente em Ruby ou JavaScript. Sob o capô, descobrimos que essa biblioteca é baseada no analisador rudimentar de PHP. Mas, no entanto, é rápido o suficiente e estável para nos adequar.

A biblioteca de filtros está disponível em github.com/crysalead/filter e pode ser usada da seguinte maneira.

Primeiramente, o patcher de código JIT deve ser inicializado o mais rápido possível (por exemplo, imediatamente após ligar o compositor de autoloade):

include __DIR__ . '/../vendor/autoload.php'; use Lead\Filter\Filters; Filters::patch(true); 

Observe que a edição de código só é possível para classes carregadas pelo compositor autoload'er. Se uma classe for adicionada usando as expressões require ou include, ela já será carregada antes de chamar Filters :: patch (true) e, portanto, não será corrigida.

Por padrão, todo o código corrigido será armazenado em / tmp / jit, mas você sempre pode alterá-lo por conta própria:

 Filters::patch(true, ['cachePath' => 'my/cache/path/jit']); 

Os arquivos em cache serão restaurados automaticamente sempre que você alterar um arquivo PHP.

Atenção! Filters::patch(true) é a maneira mais fácil de configurar o patcher, lembre-se de que todo o seu código será corrigido. Pode levar muito tempo para agrupar todos os métodos em sua base de código em um fechamento de filtro.

Felizmente, se a funcionalidade de ponta a ponta desempenha um papel crucial em códigos bem projetados, apenas alguns métodos são necessários no projeto. Portanto, a abordagem preferida é corrigir apenas os métodos que serão filtrados:

 Filters::patch([ 'A\ClassName', 'An\Example\ClassName::foo', 'A\Second\Example\ClassName' => ['foo', 'bar'], ], [ 'cachePath' => 'my/cache/path/jit', ]); 

Assim, você pode optar por corrigir todos os métodos de uma determinada classe, apenas um método ou vários deles.

Filtro de API


Agora que o JIT patcher está ativado, crie um filtro de log:

 use Chaos\Filter\Filters; use Chaos\Database\Database; use Monolog\Logger; use Monolog\Handler\StreamHandler; $logger = new Logger('database'); $logger->pushHandler(new StreamHandler('my/log/path/db.log', Logger::WARNING)); Filters::apply(Database::class, 'query', function($next, $sql, $data, $options) use ($logger) { $logger->info('Ran SQL query: ' . $sql); return $next($sql, $data, $options); }); 

O exemplo acima cria um filtro de log de consulta SQL para a biblioteca de banco de dados do Chaos. Mais informações sobre o filtro da API podem ser encontradas em github.com/crysalead/filter .

Conclusão


AOP, na minha opinião, é a resposta real para a funcionalidade de ponta a ponta. Todas as outras abstrações são igualmente redundantes e, na maioria dos casos, limitadas a uma determinada estrutura. Não perco a esperança de que um dia o PHP forneça uma API interna para programação orientada a aspectos. Mas agora, penso, o patch de código JIT é a melhor opção, onde as vantagens superam em muito a sobrecarga da CPU, que pode ser praticamente negligenciada quando o patch de código JIT não é aplicado globalmente.

O FIM

Como sempre, esperamos, se houver alguma coisa, perguntas, um desejo e convidamos você para uma aula aberta, onde você pode ouvir uma palestra interessante e conhecer melhor o novo professor .

Source: https://habr.com/ru/post/pt415713/


All Articles