【问题标题】:How to move listener code from closure to method and pass arguments to it in ZF2?如何将侦听器代码从闭包移动到方法并在 ZF2 中将参数传递给它?
【发布时间】:2015-11-12 12:52:16
【问题描述】:

我有一个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 语句的闭包中移动到单独的方法中并向其传递参数?

【问题讨论】:

    标签: php event-handling zend-framework2 closures


    【解决方案1】:

    您可以做的是将 foo 作为模块类的属性 然后用$this-&gt;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...
                ...
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答!是的,这在技术上是可行的,我可以将其用作工作场所。不过,我想找到一种干净(-er)的方法来解决这个问题。
    【解决方案2】:

    将您的方法移至侦听器类。

    一个监听器只需要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);
        ...
    }
    

    这是一些额外的工作,但它更好地分离了关注点,并且您现在有一个独立的侦听器,您可以重用它,而不是依赖于 Module 类的复制/粘贴方法。

    【讨论】:

      猜你喜欢
      • 2019-03-29
      • 2021-09-30
      • 2010-09-20
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      • 2017-08-27
      • 2020-07-12
      相关资源
      最近更新 更多