Зачем использовать Service Manager в Zend Framework 2?

скажем, у меня есть сервис:

namespace Helloworld\Service; class GreetingService { public function getGreeting() { if(date("H") <= 11) return "Good morning, world!"; else if (date("H") > 11 && date("H") < 17) return "Hello, world!"; else return "Good evening, world!"; } } 

и я создаю для него invokable

 public function getServiceConfig() { return array( 'invokables' => array( 'greetingService' => 'Helloworld\Service\GreetingService' ) ); } 

то в моем контроллере я мог бы сделать:

 public function indexAction() { $greetingSrv = $this->getServiceLocator() ->get('greetingService'); return new ViewModel( array('greeting' => $greetingSrv->getGreeting()) ); } 

предположительно это делает контроллер зависимым от службы (и ServiceManager)

и лучшим решением является создание фабрики для этой службы или возврат закрытия в ServiceManager и создание сеттера в контроллере:

 class IndexController extends AbstractActionController { private $greetingService; public function indexAction() { return new ViewModel( array( 'greeting' => $this->greetingService->getGreeting() ) ); } public function setGreetingService($service) { $this->greetingService = $service; } } 

а также

 'controllers' => array( 'factories' => array( 'Helloworld\Controller\Index' => function($serviceLocator) { $ctr = new Helloworld\Controller\IndexController(); $ctr->setGreetingService( $serviceLocator->getServiceLocator() ->get('greetingService') ); return $ctr; } ) ) 

Почему мой вопрос? Почему второй подход лучше первого? и что означает, что controller is dependent of the service ?

благодаря

ServiceManager по умолчанию вводится в любой контроллер ZF2, поскольку он расширяет AbstractController реализуя интерфейс ServiceLocatorAwareInterface .

Второй подход имеет форму « избыточности », поскольку, помимо того, что у вас уже есть доступ к экземпляру ServiceManager , всякий раз, когда вам нужно делиться своим сервисом между вашими контроллерами, вам необходимо настроить для каждого из них механизм инъекции. Поскольку у ваших контроллеров уже есть зависимость от ServiceManager, было бы разумнее использовать первый подход и зарегистрировать ваши связанные с доменом службы в ServiceManager , тем самым централизуя доступ к слою службы.

Примечание. Следующая часть ответа может выходить за рамки вопроса, но она направлена ​​на предоставление «скрытого» фона исходного.

Предположим, что мы строим сложную систему, в которой продвигаются низкоуровневые, повторно используемые и тестовые возможности. Наша система многослойна, и мы построили все до уровня обслуживания. Обратите внимание, что до сих пор мы еще не рассматривали веб-уровень MVC или даже выбирали данную структуру.

В пределах нашего уровня обслуживания (я рассмотрю этот уровень, как он упоминается в вопросе), мы предполагаем, что мы приняли принцип разделения между бизнес-логикой и конструкцией Graph Object (или разрешением зависимостей). Таким образом, у нас есть, вероятно, несколько сложных услуг, которые создаются на заводах.

Теперь, когда наш сервисный уровень построен, мы решили «подключить» его выше ZF2. Естественно, наши сервисы должны быть доступны из контроллеров, так как ваш вопрос иллюстрирует это, у нас есть больше, чем способ сделать это. Однако мы хотим избежать избыточности и использовать то, что мы уже создали. Давайте предположим следующую фабрику:

 //The following class is a part of our Service layer public class ComplexServiceFactory{ private dependencyA; private dependencyB; public function buildComplexService() { $service = new ComplexService(); $service->setDependencyA($this->dependecyA); $service->setDependencyB($this->dependecyB); return $service; } } 

Теперь мы должны просто отрегулировать (фактически расширить) нашу фабрику, чтобы она стала пригодной для использования логикой ServiceManager . Этот класс можно рассматривать как часть механизма, используемого для «подключения» нашей системы к ZF2 (это фактически адаптер )

 public class SMComplexServiceFactory extends ComplexServiceFactory implements Zend\ServiceManager\FactoryInterface { public function createService(ServiceLocatorInterface $sm) { $this->setDependencyA($sm->get('dependecyA')); $this->setDependencyB($sm->get('dependecyB')); return parent::buildComplexService; } } 

Поступая таким образом, мы не воспитываем построение графика объекта до уровня MVC (иначе это было бы нарушение Разделения проблем и ненужное межслойное соединение) . Сервис-менеджер + наши классы «Адаптированные» фабрики в некотором смысле являются нашим механизмом разрешения зависимостей. Дело в том, что наша Система по-прежнему переносима, мы могли бы, например, выбрать другую систему (другую структуру) и иметь низкую зависимость от платформы MVC.

Очень полезный вопрос. Он неоднократно поднимался. Я думаю, вы можете получить ТОЧНЫЙ ОТВЕТ ЗДЕСЬ

Чтобы добавить что-то в @yechabbis, ответьте:

Заводская схема ServiceConfiguration действительно для сложной инфраструктуры или просто не использует функции closures / callable functions внутри конфигурации. Это по двум причинам:

  • Код читаемости / очистки
  • Представление

Настройка фабричного шаблона внутри getServiceConfig приятная, чистая и быстрая. Никакие классы не создаются, но при вызове ключевого ключа службы. Если, однако, вы настраиваете службы, используя шаблон закрытия или вызываемую функцию, тогда эти классы будут всегда создаваться при каждом отдельном запросе!

Вероятно, это всего лишь пример, но код, который вы показали, также лучше всего использовать в качестве ViewHelper

Я думаю, что второй подход лучше, что делает класс контроллера независимым от GreetingService. Этот подход будет полезен, если вы хотите использовать другую службу приветствия, которая будет потребляться контроллером. Вам вообще не нужно изменять код в классе контроллера, вместо этого вы делаете это, меняя диспетчер служб с закрытием фабрики.

Я считаю, что это основная идея инверсии управления или инъекции зависимостей, вся проводка и конфигурация выполняются вне класса (в данном случае: класс контроллера).

Итак, по моему мнению, именно поэтому второй подход является лучшим.