Zend framework2 Zend Framework 2在ListenerAggregateInterface中分离侦听器

Zend framework2 Zend Framework 2在ListenerAggregateInterface中分离侦听器,zend-framework2,Zend Framework2,我实现了一个ListenerAggregateInterface,用于监听调度(MvcEvent::EVENT\u dispatch)事件 如果shortcutuit中的某些条件为true则应跳过其余侦听器。因此,我调用ListenerAggregateInterface::detach删除所有侦听器 public function shortCircuit(MvcEvent $e) { if(condition) { $this->detach($e->getAppli

我实现了一个
ListenerAggregateInterface
,用于监听调度(
MvcEvent::EVENT\u dispatch
)事件

如果
shortcutuit
中的某些条件为
true
则应跳过其余侦听器。因此,我调用
ListenerAggregateInterface::detach
删除所有侦听器

public function shortCircuit(MvcEvent $e) {
  if(condition) {
    $this->detach($e->getApplication()->getEventManager());
  }
}

我原以为它们现在不会再被执行了,但事实并非如此。

没有必要将自己的短路作为一种限制。您只需使用
$event->stopPropagation(true)

比如说

public function shortCircuit(MvcEvent $e) {
    if(condition) {
        $e->stopPropagation(true);
    }
}

没有必要把自己的短路当作一个问题来解决。您只需使用
$event->stopPropagation(true)

比如说

public function shortCircuit(MvcEvent $e) {
    if(condition) {
        $e->stopPropagation(true);
    }
}

分派侦听器时,分离当前触发事件的侦听器将不起作用。这是因为为了按优先级对它们进行排序

停止传播也不适用于当前方法,因为您只想禁用一组特定的侦听器

public function shortCircuit(MvcEvent $e) {
  if(condition) {
    $this->detach($e->getApplication()->getEventManager());
  }
}
不过,有一个解决方案,就是只在需要时跳过侦听器,使用一个小注册表记录聚合侦听器要跳过的事件。我把它写在了头上,所以它是未经测试的,如果你想使用它,请仔细进行单元测试:

使用SplObjectStorage;
使用Zend\EventManager\EventInterface;
最终类跳过了EventsRegistry{
/**@var SplObjectStorage*/
私人$skippedEvents;
公共函数构造(){
$this->skippedEvents=new SplObjectStorage();
}
/**
*@param callable$callback
*@return callable
*/
公共函数buildCallback(可调用$callback)
{
返回函数($event)使用($callback){
如果(isset($this->skippedEvents[$event])){
返回;
}
返回$callback($event);
};
}
公共函数SkipListenerForEvent(EventInterface$event){
$this->skippedEvents[$event]=$event;
}
公共功能RestoreListenerForEvent(EventInterface$event){
取消设置($this->skippedEvents[$event]);
}
}
然后在聚合侦听器中使用此注册表:

使用Zend\EventManager\EventInterface;
使用Zend\EventManager\EventManager接口;
使用Zend\EventManager\ListenerAggregateInterface;
使用Zend\EventManager\listeneraggregait;
类MyAggregateListener实现ListenerAggregateInterface{
使用listeneraggrageit;
私人$skippedEvents;
公共函数构造(){
$this->skippedEvents=新SkippedEventsRegistry();
}
公共函数附加(EventManagerInterface$events){
$this->listeners[]=$events->attach('SomeEvent',
$this->skippedEvents->buildCallback(函数($event){
//…在这里做其他事情。。。
如果($worldIsExploding){
//开始跳过其他侦听器
$this->skippedEvents->skipListenersForEvent($event);
}
}), 9999);
$this->listeners[]=$events->attach('SomeEvent',
$this->skippedEvents->buildCallback(函数($event){
//…在这里做其他事情。。。
}), 8888);
//重置正常执行
//(不幸的是,只有在传播没有停止的情况下才会发生)
$this->listeners[]=$events->attach(
“某件事”,
[$this->skippedEvents,'restoreListenerForEvent'],
-9999999999
);
}
}
(很抱歉对齐混乱,但很难将所有内容都放入溢出中:\)

如您所见,我们只是在注册表中将事件标记为“跳过”时阻止侦听器执行。在第一个侦听器执行期间,
$worldIsExploding=true
会发生这种情况

之后,我们执行所有其他侦听器,并在最后通过低优先级侦听器进行清理


最后,您还可以在具有高优先级的事件侦听器中调用
$this->skippedEvents->restoreListenerForEvent($event)
。这可以防止跳过侦听器,即使同一个
$event
实例用于多个
Zend\EventManager\EventManagerInterface#trigger()
调用。

分派侦听器时,为当前触发的事件分离侦听器将不起作用。这是因为为了按优先级对它们进行排序

停止传播也不适用于当前方法,因为您只想禁用一组特定的侦听器

public function shortCircuit(MvcEvent $e) {
  if(condition) {
    $this->detach($e->getApplication()->getEventManager());
  }
}
不过,有一个解决方案,就是只在需要时跳过侦听器,使用一个小注册表记录聚合侦听器要跳过的事件。我把它写在了头上,所以它是未经测试的,如果你想使用它,请仔细进行单元测试:

使用SplObjectStorage;
使用Zend\EventManager\EventInterface;
最终类跳过了EventsRegistry{
/**@var SplObjectStorage*/
私人$skippedEvents;
公共函数构造(){
$this->skippedEvents=new SplObjectStorage();
}
/**
*@param callable$callback
*@return callable
*/
公共函数buildCallback(可调用$callback)
{
返回函数($event)使用($callback){
如果(isset($this->skippedEvents[$event])){
返回;
}
返回$callback($event);
};
}
公共函数SkipListenerForEvent(EventInterface$event){
$this->skippedEvents[$event]=$event;
}
公共功能RestoreListenerForEvent(EventInterface$event){
取消设置($this->skippedEvents[$event]);
}
}
然后在聚合侦听器中使用此注册表:

使用Zend\EventManager\EventInterface;
使用Zend