事件调度是一种常见且经过充分测试的机制,允许开发人员轻松,一致地将逻辑注入应用程序。
此PSR的目标是为基于事件的扩展和协作建立一个通用机制,以便可以在各种应用程序和框架之间更自由地重用库和组件。
本文件中的关键词“必须”,“不得”,“必须”,“应该”,“不应该”,“应该”,“不应该”,“推荐”,“可以”和“可选”按照RFC 2119中的描述进行解释。
具有用于调度和处理事件的公共接口允许开发人员创建可以以常见方式与许多框架和其他库交互的库。
一些例子:
事件是充当发射器和适当的监听器之间通信单元的对象。
如果用例调用Listeners将信息提供给Emitter,则事件对象可能是可变的。但是,如果不需要这样的双向通信,则建议将事件定义为不可变的; 即,定义使其缺乏mutator方法。
实现者必须假设同一个对象将被传递给所有监听器。
推荐但不是必需的,Event对象支持无损序列化和反序列化; $event == unserialize(serialize($event))
应该坚持。对象可以利用PHP的Serializable
接口,__sleep()
或者__wakeup()
魔术方法,或者如果合适的话类似的语言功能。
一个停止的事件是一个包含其他方法来防止进一步的听众被称为事件的特殊情况。它通过实施表明StoppableEventInterface
。
实现的事件StoppableEventInterface
必须true
从isPropagationStopped()
它所代表的任何事件完成时返回。由类的实现者来决定何时是。例如,要求PSR-7 RequestInterface
对象与相应ResponseInterface
对象匹配的事件可能有setResponse(ResponseInterface $res)
一个监听器调用的方法,这会导致isPropagationStopped()
返回true
。
监听器可以是任何PHP可调用的。监听器必须只有一个参数,即它响应的事件。监听器应该键入提示该参数具体与其用例相关; 也就是说,监听器可以对接口键入提示,以指示它与实现该接口的任何事件类型或该接口的特定实现兼容。
监听器应该有一个void
返回,并且应该显式返回SHOULD类型提示。Dispatcher必须忽略Listeners的返回值。
监听器可以将操作委托给其他代码。这包括一个Listener,它是一个运行实际业务逻辑的对象的瘦包装器。
监听器可以使用cron,队列服务器或类似技术将来自事件的信息排入队列,以便稍后由辅助进程处理。它可以序列化Event对象本身; 但是,应注意并非所有Event对象都可以安全地序列化。辅助进程必须假定它对Event对象所做的任何更改都不会传播给其他Listener。
Dispatcher是一个实现的服务对象EventDispatcherInterface
。它负责从侦听器提供程序检索侦听器的侦听器,并使用该事件调用每个侦听器。
调度员:
如果传递了一个Stoppable事件,一个Dispatcher
isPropagationStopped()
每个Listener之前调用Event。如果该方法返回true
它必须立即将事件返回给发射器,并且不得再调用任何进一步的监听器。这意味着,如果一个事件被传递到总是返回调度true
从isPropagationStopped()
零名听众将被调用。Dispatcher应该假设从Listener Provider返回给它的任何Listener都是类型安全的。也就是说,Dispatcher应该假设调用$listener($event)
不会产生TypeError
。
监听器抛出的异常或错误必须阻止任何进一步监听器的执行。监听器抛出的异常或错误必须允许传播回发射器。
Dispatcher可以捕获抛出的对象来记录它,允许采取其他操作等,但是必须重新抛出原始的throwable。
监听器提供程序是一个服务对象,负责确定哪些监听器与给定事件相关并应该被调用。它可以确定听众的相关性以及通过它选择的任何方式返回它们的顺序。可能包括:
可以根据需要使用上述或其他机制的任何组合。
监听器提供者应该使用事件的类名来区分一个事件和另一个事件。他们也可以酌情考虑有关该事件的任何其他信息。
在确定监听器适用性时,监听器提供者必须将父类型与事件自身类型完全相同。在以下情况中:
class A {}
class B extends A {}
$b = new B();
function listener(A $event): void {};
监听器提供者必须将其listener()
视为适用的监听器$b
,因为它是类型兼容的,除非某些其他标准阻止它这样做。
Dispatcher应该组成一个监听器提供程序来确定相关的监听器。建议将侦听器提供程序实现为Dispatcher的不同对象,但这不是必需的。
namespace Psr\EventDispatcher;
/**
* Defines a dispatcher for events.
*/
interface EventDispatcherInterface
{
/**
* Provide all relevant listeners with an event to process.
*
* @param object $event
* The object to process.
*
* @return object
* The Event that was passed, now modified by listeners.
*/
public function dispatch(object $event);
}
namespace Psr\EventDispatcher;
/**
* Mapper from an event to the listeners that are applicable to that event.
*/
interface ListenerProviderInterface
{
/**
* @param object $event
* An event for which to return the relevant listeners.
* @return iterable[callable]
* An iterable (array, iterator, or generator) of callables. Each
* callable MUST be type-compatible with $event.
*/
public function getListenersForEvent(object $event) : iterable;
}
namespace Psr\EventDispatcher;
/**
* An Event whose processing may be interrupted when the event has been handled.
*
* A Dispatcher implementation MUST check to determine if an Event
* is marked as stopped after each listener is called. If it is then it should
* return immediately without calling any further Listeners.
*/
interface StoppableEventInterface
{
/**
* Is propagation stopped?
*
* This will typically only be used by the Dispatcher to determine if the
* previous listener halted propagation.
*
* @return bool
* True if the Event is complete and no further listeners should be called.
* False to continue calling listeners.
*/
public function isPropagationStopped() : bool;
}