у меня есть 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
оператор в отдельный метод и передать ему аргументы?
Что вы можете сделать, это переместить 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...
...
}
}
Вы также можете заставить функцию в модуле возвращать Closure, где вы используете $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...
...
}
}
}
Переместите ваш метод в класс слушателя.
Слушатель просто должен быть 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.