PSR-14: Um grande evento em PHP

,

O PHP Framework Interoperability Group ( PHP-FIG ) lançou várias novas especificações no ano passado. O mais recente, o PSR-14 , abrange o
Event Dispatching . Como muitos PSRs, é uma especificação bastante pequena, no final do dia, mas destinada a ser de alto impacto.

Nesta série de posts eu quero cobrir o que o PSR-14 é e faz (e o que não é e o que não faz), e como melhor aproveitá-lo em seus projetos à medida que ele é implementado mais amplamente.

O objetivo

O Event Dispatching existe há muito tempo, em várias formas, em muitas linguagens. Se você já usou o EventDispatcher do Symfony , o sistema de eventos do Laravel , Drupal hooks , o gerenciador de eventos do Zend Framework , o League\Eventpackage ou qualquer coisa nesse sentido, é disso que estamos falando.

Mais genericamente, todos esses sistemas são uma forma de “observador mediado”. Um pedaço de código emite uma mensagem de algum tipo (um “Evento”), e um mediador passa essa mensagem para outros pedaços de código desacoplados (geralmente chamados de “Ouvintes – [Listeners] “). Às vezes é mono-direcional, outras vezes esses outros pedaços de código podem passar dados de volta para o chamador de alguma forma. Eles são todos, é claro, diferentes e incompatíveis.

Isso cria um problema para bibliotecas independentes que desejam conectar-se a vários frameworks e aplicativos. Muitas bibliotecas se tornam extensíveis emitindo eventos de alguma forma ou de outra para que outro código seja ligado; no entanto, essa camada mediadora é essencialmente proprietária. Uma biblioteca que injeta o EventDispatcher do Symfony é então acoplada ao Symfony; usá-lo em qualquer outro lugar requer a instalação do EventDispatcher e a ponte para qualquer sistema de eventos da estrutura. Uma biblioteca que chama o module_invoke_all()
hook system do Drupal é então acoplada ao Drupal. E assim por diante.

O objetivo do PSR-14, então, é abstrair essa dependência. Ele permite que as bibliotecas se exponham à extensão por meio de uma fina camada genérica, o que torna muito simples descartá-las no Symfony, no Zend Framework, no Laravel, no TYPO3, no eZ Platform, no Slim ou em qualquer outro ambiente sem sobrecarga extra. Contanto que esse ambiente tenha alguma implementação compatível com o PSR-14, ele funcionará.

A especificação

Como mencionado, a especificação em si é bastante fina. Na verdade, são apenas três interfaces de método único, além de uma meta descrição sobre como usá-las. Isso é uma coisa boa. Vamos dar uma olhada neles (comentários removidos para economizar espaço):

namespace Psr\EventDispatcher;

interface EventDispatcherInterface
{
    public function dispatch(object $event);
}

interface ListenerProviderInterface
{
    public function getListenersForEvent(object $event) : iterable;
}

interface StoppableEventInterface
{
    public function isPropagationStopped() : bool;
}

Os dois primeiros são o núcleo da especificação; StoppableEventInterface é uma extensão para a qual chegaremos mais tarde.

O despachante deve ser bastante familiar para a maioria; é apenas um objeto com um método para o qual você passa um Evento, isto é, o mediador que mencionamos anteriormente. O evento em si, no entanto, não está definido; o evento pode ser qualquer objeto PHP. Mais sobre isso depois.

Atualmente, a maioria das implementações existentes tem um único objeto (ou conjunto de funções) que atua como um mediador / dispatcher e um local para registrar o código que recebe cada evento (Listeners). Para o PSR-14, deliberadamente dividimos essas duas responsabilidades em objetos separados. O Dispatcher obtém a lista de ouvintes de um objeto Provider, que compõe.

Onde o Provider obtém seus Listeners ? De qualquer lugar que ele quiser! Há um zilhão e uma maneira de associar um Listeners a um evento, todos eles completamente válidos e todos eles incompatíveis. Decidimos desde o início que a padronização do One True Way ™ de registrar
Listeners seria muito limitadora. No entanto, ao padronizar como colocar os Listeners no Dispatcher, ainda podemos oferecer uma grande flexibilidade sem restringir demais a capacidade dos implementadores de fazer todo tipo de coisas estranhas.

Também não especificado em código é como os ouvintes se parecem. Os ouvintes podem ser chamados de qualquer PHP: uma função, uma função anônima, um método de um objeto, qualquer que seja. Como um callable pode fazer qualquer coisa, isso significa que também é trivialmente fácil e totalmente legítimo ter um Listener, digamos, uma função anônima que carrega preguiçosamente um serviço de um contêiner de injeção de dependência e chama um método nele, que é o código. que foi realmente registrado.

Em resumo, o Dispatcher fornece uma API simples e leve para autores de bibliotecas. Os provedores de Listener oferecem uma API robusta e flexível para integradores de framework. E a relação entre Dispatcher/Provider liga os dois juntos.

Um exemplo trivial

O esboço mais básico de como todas as partes se encaixam, então, seria algo como isto:

class Dispatcher implements EventDispatcherInterface
{

   public function __construct(ListenerProviderInterface $provider)
   {
       $this->provider = $provider;
   }

   public function dispatch(object $event)
   {
       foreach ($this->provider->getListenersForEvent($event) as $listener) {
           $listener($event);
       }
       return $event;
   }
}

$dispatcher = new Dispatcher($provider);

$event = new SomethingHappened();
$dispatcher->dispatch($event);

Esse pequeno código, no entanto, abre um grande poder e flexibilidade. No restante desta série, vou aprofundar ainda mais, aprofundando algumas das decisões de design e uma amostra das muitas, muitas maneiras pelas quais os Eventos leves podem ser usados.

Código

O PSR-14 já conta com suporte dos principais frameworks e aplicativos:

  • Matthew Weier O’Phinney, do Zend Framework, já se comprometeu a apoiá-lo no zend-eventmanager 4.0 (em breve).
  • O Symfony acaba de anunciar mudanças no componente EventDispatcher para alinhá-lo com o PSR-14, que abre o caminho para suportar o PSR-14 diretamente em 5.0 / 5.1.
  • A estrutura do Yii declarou sua intenção de adotar o PSR-14 na versão 3.0 .
  • Benni Mack, do TYPO3 CMS, afirmou que o TYPO3 migrará todos os seus conceitos de hook + signal / slot existentes em favor do PSR-14 na próxima versão.

Há também três implementações independentes totalmente funcionais disponíveis que você pode usar hoje em qualquer aplicativo:

Todos estão a um composer require de distância. Discutirei mais detalhadamente posteriormente na série.

Créditos

Eu quero deixar a lista dos membros de todo o Grupo de Trabalho do PSR-14:

Autor: Larry Garfield

Artigo Original

Obrigado por enviar o seu comentário minha jóia!