我有一个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 SomeModuleListener;
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 SomeModuleFactory;
use ZendServiceManagerFactoryInterface;
use ZendServiceManagerServiceLocatorInterface;
class BazListenerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $services)
{
//fetch foo from wherever ..
$foo = ;
return new SomeModuleListenerBazListener($foo);
}
}
现在将侦听器工厂添加到服务管理器中,以便您可以在onBootstrap
中访问它return array(
'service_manager' => (
'factories' => (
// ..
'SomeModuleListenerBazListener' => 'SomeModuleFactoryBazListenerFactory',
// ..
),
),
);
最后从onBootstrap中的服务管理器中获取侦听器作为服务,并将其附加到事件管理器
public function onBootstrap(MvcEvent $mvcEvent)
{
$bazListener = $mvcEvent->getApplication()
->getServiceManager()
->get('SomeModuleListenerBazListener');
$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...
...
}
}
}