Я бы сказал, нет, не передавайте контейнер конфигурации - ни как службу, ни как массив, ни как экземпляр Zend_Config
- в конструкторе других ваших служб. Я бы оставил инъекцию (будь то конструктором или установщиком) для этих сервисов, ориентированных на фактические объекты/соавторы/данные, которые им действительно нужны.
Так, например, ArticleService
может зависеть от интерфейса/объекта ArticleRepository
, или от ArticleMapper
, или от адаптера базы данных. Пусть сигнатуры конструктора/сеттера для ArticleService
отражают то, что ему действительно нужно.
Вместо этого я бы во время Bootstrap
создал какой-то фабричный объект - возможно, в качестве ресурса приложения - который принимает в своем конструкторе ваши данные/объект/службу конфигурации (или, что еще лучше, сам экземпляр начальной загрузки, из которого вы могли бы получить , не только ваши данные конфигурации, но и любые ресурсы приложения, такие как адаптер базы данных, которые были созданы в процессе начальной загрузки). Затем напишите методы для вашего фабричного объекта, которые создают/доставляют другие необходимые вам сервисы. Внутри фабрика ведет реестр уже созданных сервисов, чтобы при необходимости можно было отложенно создавать экземпляры.
Фрагмент того, что я имею в виду, может быть следующим:
Фрагмент начальной загрузки:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initFactory()
{
$factory = new My_Factory($this);
return $factory;
}
}
Затем завод:
class My_Factory
{
protected $_registry;
protected $_bootstrap;
public function __constructor($bootstrap)
{
$this->_bootstrap = $bootstrap;
}
public function getDbAdapter()
{
if (!isset($this->_registry['dbAdapter']){
$this->_bootstrap->bootstrap('db'); // probably using app resource
$this->_registry['dbAdapter'] = $This->_bootstrap->getResource('db');
}
return $this->_registry['dbAdapter'];
}
public function getArticleService()
{
if (!isset($this->_registry['articleService']){
$dbAdapter = $this->getDbAdapter();
$this->_registry['articleService'] = new My_ArticleService($dbAdapter);
}
return $this->_registry['articleService'];
}
public function getTwitterService()
{
if (!isset($this->_registry['twitterService']){
$options = $this->_bootstrap->getOptions();
$user = $options['twitter']['user'];
$pass = $options['twitter']['pass'];
$this->_registry['twitterService'] = new My_TwitterService($user, $pass);
}
return $this->_registry['twitterService'];
}
}
Затем в контроллере вы можете получить экземпляр ArticleService
:
class SomeController extends Zend_Controller_Action
{
protected $_factory;
public function init()
{
$this->_factory = $this->getInvokeArg('bootstrap')->getResource('factory');
}
public function someAction()
{
$articleService = $this->_factory->getArticleService();
$this->view->articles = $articleService->getRecentArticles(5); // for example
}
}
В результате каждый сервис явно идентифицирует нужных ему соавторов, а фабрика — это единое место, которое заботится о создании/внедрении всех этих соавторов.
Наконец, я признаюсь, что я просто плююсь здесь. Для меня это, по сути, рудиментарный контейнер для внедрения зависимостей; в этом смысле использование полнофункционального DIC — возможно, Symfony DIC или нового пакета Zend\Di
в ZF2 — может быть лучше. Но после многих месяцев борьбы со всеми рекомендациями по внедрению ваших зависимостей я пришел к этому. Если это глупо или просто неправильно, пожалуйста (пожалуйста!) поправьте меня. ;-)
person
David Weinraub
schedule
17.06.2011