如何在ZF2中将侦听器代码从闭包移动到方法并向其传递参数


How to move listener code from closure to method and pass arguments to it in ZF2?

我有一个Module类,它的onBootstrap(...)中有多个"内联"事件侦听器:

...
class Module
{
    public function onBootstrap(MvcEvent $mvcEvent)
    {
        ...
        $foo = ...;
        ...
        $halPlugin = $viewHelperManager->get('Hal');
        $halPlugin->getEventManager()->attach('bar', function ($event) {
            ...
        });
        ...
        $halPlugin->getEventManager()->attach('baz', function ($event) use ($foo)
        {
            ...
        });
        ...
    }
    ...
}

现在,为了保持/使Module#onBootstrap(...)苗条,我想将侦听器从闭包移动到单独的方法。对于onBar事件侦听器来说,这没有问题。但它不适用于onBaz,需要额外的输入:

...
class Module
{
    public function onBootstrap(MvcEvent $mvcEvent)
    {
        ...
        $halPlugin->getEventManager()->attach('bar', [$this, 'onBar']);
        ...
    }
    ...
    public function onBar()
    {
        ...
    }
    public function onBaz() // <-- How to pass $foo to the method?
    {
        // Some stuff, that needs $foo...
        ...
    }
}

在最初的变体中,这个输入是通过use指令传递到闭包中的。但现在该怎么做呢?

如何将事件侦听器的逻辑(附在Module#onBootstrap(...)中)从具有use语句的闭包移动到单独的方法并将参数传递给它?

将方法移动到侦听器类。

一个监听器只需要是Callable,这意味着在你的类中声明__invoke()方法,并将所有的代码放在你当前的onBaz()方法

<?php
namespace SomeModule'Listener;
class BazListener
{
    protected $foo;
    public function __construct($foo)
    {
        $this->foo = $foo;
    }
    public function __invoke()
    {
         // code from onBaz() method using $this->foo
    }
}

你会注意到$foo现在是一个需要注入构造函数的依赖项。为了实现依赖,为侦听器类编写一个工厂,在工厂中获取$foo并将其注入到那里。

<?php
namespace SomeModule'Factory;
use Zend'ServiceManager'FactoryInterface;
use Zend'ServiceManager'ServiceLocatorInterface;
class BazListenerFactory implements FactoryInterface
{
     public function createService(ServiceLocatorInterface $services)
     {
          //fetch foo from wherever ..
          $foo = ;
          return new 'SomeModule'Listener'BazListener($foo);
     }
}

现在将侦听器工厂添加到服务管理器中,以便您可以在onBootstrap

中访问它
return array(
     'service_manager' => (
         'factories' => (
             // ..
             'SomeModule'Listener'BazListener' => 'SomeModule'Factory'BazListenerFactory',
             // ..
         ),
    ),
);

最后从onBootstrap中的服务管理器中获取侦听器作为服务,并将其附加到事件管理器

public function onBootstrap(MvcEvent $mvcEvent)
{
    $bazListener = $mvcEvent->getApplication()
                            ->getServiceManager()
                            ->get('SomeModule'Listener'BazListener');
    $halPlugin->getEventManager()->attach('bar', $bazListener);
    ...
}

这是一点额外的工作,但它更好地分离关注点,你现在有一个独立的监听器,你可以重用,而不是依赖于复制/粘贴方法从模块类。

你能做的就是把foo作为模块类的属性然后输入$this->foo

class Module
{
    private $foo;
    public function onBootstrap(MvcEvent $mvcEvent)
    {
        $this->foo = ...;
        $halPlugin->getEventManager()->attach('baz', [$this, 'onBaz']);
        ...
    }
    ...
    public function onBaz()
    {
        $this->foo
        // Some stuff, that needs $foo...
        ...
    }
}

你也可以让模块中的函数返回一个闭包,在那里你使用$foo与函数一起发送。

class Module
{
    public function onBootstrap(MvcEvent $mvcEvent)
    {
        $foo = ...;
        $halPlugin->getEventManager()->attach('baz', $this->onBaz($foo));
        ...
    }
    ...
    public function onBaz($foo)
    {
        return function ($event) use ($foo) {
            $this->foo
            // Some stuff, that needs $foo...
            ...
        }
    }
}