alex-patterson-webdev / event-dispatcher
PSR-14 事件分发器的简单实现
Requires
- php: >=8.1
- psr/event-dispatcher: ^1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.6.0
- mockery/mockery: ^1.5
- phpspec/prophecy: ^1.15.0
- phpstan/phpstan: ^1.4.8
- phpstan/phpstan-mockery: ^1.1
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.6
Provides
README
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\ListenerProvider
是 Psr\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