Базовым элементом пакета является класс Zend\ServiceManager\ServiceManager, реализующий интерфейс Zend\ServiceManager\ServiceLocatorInterface и включающий следующие основные методы:
setAllowOverride - определяет возможность перезаписывать уже установленные сервисы
Учтите, что интерфейс ServiceLocatorInterface наследует Interop\Container\ContainerInterface и дополняет его методом build, все же остальные методы являются нестандартными расширениями ZendFramework.
Каждый конкретный метод данного класса более подробно обсуждается ниже, а пока рассмотрим постой пример использования:
Помните, что по умолчанию нельзя добавлять Локатору служб сервис, который уже был зарегистрирован в нем ранее. Для обхода этого ограничения необходимо сконфигурировать локатор с помощью следующего вызова: $locator->setAllowOverride(true).
Класс Zend\ServiceManager\AbstractPluginManager является абстрактной реализацией интерфейса Zend\ServiceManager\PluginManagerInterface и отличает от Локатора служб только тем, что ограничивает свою область ответственности только сервисами конкретных классов. Это удобно, если вам необходимо использовать Локатор служб для хранения и предоставления, к примеру, Контроллеров или Хелперов представления.
Для реализации собственного Менеджера плагинов можно использовать как собственную реализацию интерфейса PluginManagerInterface, так и расширение абстракции AbstractPluginManager.
Через реализацию интерфейса:
Через расширение абстракции:
Через переопределение абстракции:
Как, возможно, вы уже заметили, PluginManager может быть проинициализирован сервисами в момент объявления, для этого достаточно проинициализировать следующие его свойства (в листинге приведены примеры инициализации):
При инстанциации такого Менеджера плагинов, он будет заполнен указанными сервисами и готов к использованию. Часто это применяется для создания небольшого локатора, на пример так - Менеджер плагинов для Хелперов представления.
Сервисы
Сервисами в ZendFramework могут являться любые данные и объекты. Их отличает то, что они создаются в момент заполнения контейнера и всегда предоставляются шарингом:
Фабрики
Фабрики позволяют создавать сервисы в момент их запроса из контейнера. В качестве фабрики может выступать как анонимная функция, так и класс, реализующий интерфейс Zend\ServiceManager\Factory\FactoryInterface:
Метод build, используемый в примерах, позволяет не только указать опции для фабрики, но и исключает шаринг, даже если он включен. В противном же случае можно использовать метод get для получения сервисов из фабрик.
При регистрации класса-фабрики можно как указать имя ее класса (как это сделано в примере), так и передать экземпляр. Во втором случае можно проинициализировать фабрику через конструктор.
Invokable-фабрики
Если вам необходима фабрика, создающая экземпляры сервиса без передачи констуктору аргументов или с заданным их набором, можно воспользоваться готовой реализацией в виде класса Zend\ServiceManager\Factory\InvokableFactory:
Метод setInvokableClass является фассадным и позволяет регистрировать InvokableFactory без прямого взаимодействия с этим классом:
Метод setInvokableClass помимо прочего, так же позволяет использовать любое имя сервиса, а не только полное имя инстанциируемого класса.
Псевдонимы
Метод setAlias позволяет зарегистрировать любой сервис или фабрику под несколькими именами:
Чаще всего это применяется в Менеджерах плагинов для сокращения имен часто используемых сервисов.
Шаринг
Шаринг позволяет кешировать созданные фабриками сервисы, что исключает повторный вызов фабрики:
Помните, что при запросе сервиса с помощью метода build, настройки шаринга не действуют.
Абстрактные фабрики
Абстрактные фабрики позволяют создавать сервисы, незарегистрированные ранее в Локаторе служб. Это может быть полезно в случае, если вам необходимо создание сервиса по умолчанию:
В отличии от обычных фабрик, абстрактные вызываются только в том случае, если сервис с данным именем не зарегистрирован и метод canCreate абстрактной фабрики возвращает true. Это позволяет зарегистрировать несколько таких фабрик, обеспечивая тем самым гарантированный возврат некотого сервиса.
Как и при регистрации обычных фабрик, метод addAbstractFactory может принимать имя класса абстрактной фабрики или его экземпляр.
Делегаторы
Делегаторы это специальные классы или анонимные функции, способные расширять или изменять функционал зарегистрированных в Локаторе служб сервисов. Они регистрируются на то же имя, что и имеющийся сервис и вызываются последовательно, взаимодействуя с сервисом по принципу “конвейера”.
В данном примере делегатор используется для внедрения зависимости в контроллер.
Инициализаторы
Инициализаторы похоже на делегаторы, но регистрируются не на конкретный сервис, а вызываются для всех доступных в Локаторе служб:
Приведенный в примере инициализатор способен работать с любыми контроллерами приложения, что упрощает конфигурацию Локатора служб (нет необходимости регистрировать делегатор для каждого контроллера в отдельности), но так же увеличивает нагрузку за счет проверки всех запрашиваемых из локатора сервисов. Учитывая это, старайтесь использовать делегатор везде, где это возможно, а инициализаторы применять только в особых случаях.
Конфигурация локатора
Класс Zend\ServiceManager\ServiceManager может быть сконфигурирован декларативно (с использованием массива PHP). Для этого используется конструктор или метод configure. При этом массив конфигурации может включать следующие ключи: