alex-patterson-webdev/event-dispatcher

PSR-14 事件分发器的简单实现

3.0.0 2023-05-08 00:21 UTC

This package is auto-updated.

Last update: 2024-09-08 04:01:51 UTC


README

github workflow codecov Scrutinizer Code Quality

Arp\EventDispatcher

关于

PSR-14 事件分发器 的实现。

安装

通过 composer 安装。

require alex-patterson-webdev/event-dispatcher ^3

用法

分发事件

Arp\EventDispatcher\EventDispatcher 类负责执行任何给定事件实例的事件监听器。事件分发器需要一个 Arp\EventDispatcher\Listener\ListenerProvider 实例作为单一依赖。该 ListenerProvider 包含所有可以分发的监听器。

use Arp\EventDispatcher\EventDispatcher;
use Arp\EventDispatcher\Listener\ListenerProvider;

$listenerProvider = new ListenerProvider();
$dispatcher = new EventDispatcher($listenerProvider);

EventDispatcher::dispatch() 的调用将遍历提供者中注册的事件监听器。任何匹配 $event 的监听器将按配置的优先级顺序执行。

$dispatcher->dispatch(new \My\Event\Foo());

任何对象都可以用作事件;默认情况下,内部 EventNameResolver 实例将返回要作为事件名称使用的对象的完全限定类名。有关更多配置选项,请参阅“事件名称解析器”部分。

事件监听器注册

Arp\EventDispatcher\Listener\ListenerProviderPsr\EventDispatcher\ListenerProviderInterface 的实现。该类被设计用来存储和“提供”给定事件对象的“可迭代”集合的事件监听器。该 ListenerProvider 还实现了接口 Arp\EventDispatcher\Listener\AddListenerAwareInterface,它公开了允许注册事件监听器的公共方法。

我们可以直接使用 ListenerProvider::addListenerForEvent() 方法注册任何 PHP callable 数据类型。

例如

use Arp\EventDispatcher\Listener\ListenerProvider;
use My\Event\Foo;

$listenerProvider = new ListenerProvider();

$event = new Foo();
$listener = static function (Foo $event) {
    echo 'The My\Event\Foo event was dispatched' . PHP_EOL;
};

$listenerProvider->addListenerForEvent($event, $listener);

我们还可以使用 addListenersForEvent() 方法附加监听器数组。

$listeners = [
    new class() {
        public function __invoke(Foo $event): void {
            echo 'Listener 1' . PHP_EOL;
        }
    },
    static function (Foo $event) {
        echo 'Listener 2' . PHP_EOL;
    },
];

$listenerProvider->addListenersForEvent($event, $listeners);

然后我们可以通过调用 $listenerProvider->getListenersForEvent($event); 获取这些事件监听器。结果是 Arp\EventDispatcher\Listener\ListenerCollectionInterface 的一个实例,它包含已添加的事件监听器。

/** @var ListenerCollectionInterface $listenerCollection */
$listenerCollection = $listenerProvider->getListenersForEvent($event);

通过事件分发器添加监听器

为了方便,EventDispatcher 类还实现了 Arp\EventDispatcher\Listener\AddListenerAwareInterface。这提供了公开的方法,允许在将监听器提供者传递给 EventDispatcher 之后,将其添加到监听器提供者的集合中。

内部调用 addListenerForEvent()addListenersForEvent() 将代理到内部监听器提供者。

use Arp\EventDispatcher\EventDispatcher;
use Arp\EventDispatcher\Listener\ListenerProvider;

$dispatcher = new EventDispatcher(new ListenerProvider());

$listener1 = static function (Foo $event) {
    echo 'Event Listener 1' . PHP_EOL;
};
$listener2 = static function (Foo $event) {
    echo 'Event Listener 2' . PHP_EOL;
};

$dispatcher->addListenerForEvent($event, $listener1);
$dispatcher->addListenerForEvent($event, $listener2);

$dispatcher->dispatch(new My\Event\Foo());

不可变事件分发器

如果您不希望修改传递给 EventDispatcher 后的事件监听器集合,可以使用提供的 Arp\EventDispatcher\ImmutableEventDispatcher。此事件分发器实现不公开任何可以更改初始监听器提供者的方法。

监听器优先级

内部,ListenerProvider 将为每个您提供的每个事件保留一个可迭代的优先队列,其中包含所有监听器。

$priority 参数允许对每个监听器进行排序。优先级更高的监听器将先于优先级较低的监听器执行。如果两个或多个监听器具有相同的优先级,它们将尊重它们被添加的顺序。

use My\Event\Foo;
use Arp\EventDispatcher\Listener\ListenerProvider;

$event = new Foo();

$listener1 = static function (Foo $event) {
    echo 'Listener 1' . PHP_EOL;
};
$listener2 = static function (Foo $event) {
    echo 'Listener 2' . PHP_EOL;
};

$listenerProvider->addListenerForEvent($event, $listener1, -100);
$listenerProvider->addListenerForEvent($event, $listener2, 100);

$eventDispatcher->dispatch($event);

// Listener 2
// Listener 1

事件名称解析器

默认情况下,EventNameResolver 将使用事件对象的完全限定类名作为将被分发的事件的名称。然而,可能会有需要将事件的名称作为事件对象的属性提供的情况。这可以通过在您的事件类上实现 Arp\EventDispatcher\Resolver\EventNameAwareInterface 或使用默认的 Arp\EventDispatcher\NamedEvent 来实现。

当一个实现 EventNameAwareInterface 的对象传递给 EventNameResolver 时,提供者将返回 getEventName() 的值。

use Arp\EventDispatcher\Event\NamedEvent;

// Dispatch the 'foo' event
$eventDispatcher->dispatch(new NamedEvent('foo'));

事件传播

根据 PSR 规范,如果提供了 Psr\EventDispatcher\StoppableEventInterface 的事件实例,调度器将尊重 isPropagationStopped() 调用的结果。如果设置为 true,则事件调度器将被阻止执行任何其他监听器。

单元测试

使用 PHPUnit 的 PHP 单元测试。

php vendor/bin/phpunit