Service Locator (Локатор служб) в Bitrix
Service Locator, это шаблон проектирования, используемый в разработке программного обеспечения для инкапсуляции процессов, связанных с получением какого-либо сервиса с сильным уровнем абстракции.
Идея соистоит в том, чтобы вместо создания конкретных объектов напрямую с помощью new, используется специальный объект ServiceLocator, который будет отвечать за создание, нахождение сервисов, своего рода реестр экземпляров.
Пример использования
$serviceLocator = \Bitrix\Main\DI\ServiceLocator::getInstance();
// проверяем, зарегистрирован ли Service Locator
if ($serviceLocator->has('название_service_locator'))
{
// получаем обьект зарегистрированного Service Locator
$someService = $serviceLocator->get('someService');
}
Режим работы
По умолчанию Service Locator работает в режиме Autowire, автоматически разрешает все зависимости у сервисов. Service Locator может автоматически создавать объекты указанных классов, даже если их нет внутри контейнера:
$serviceInstance = \Bitrix\Main\DI\ServiceLocator::getInstance()->get(\VendorName\SomeModule\Services\SomeService::class);
Конфигурация сервиса
Конфигурация определяет способ создания объекта, возможны три варианта.
Service Locator создаст сервис вызвав new $className:
'someModule.someServiceName' => [
'className' => \VendorName\SomeModule\Services\SomeService::class,
]
Service Locator создаст сервис вызвав new $className('foo', 'bar'):
'someModule.someServiceName' => [
'className' => \VendorName\SomeModule\Services\SomeService::class,
'constructorParams' => ['foo', 'bar'],
]
Замыкание создаст и вернет объект сервиса:
'someModule.someAnotherServiceName' => [
'constructor' => static function () {
return new \VendorName\SomeModule\Services\SecondService('foo', 'bar');
},
]
В качестве ключа, который реализует сервис, можно использовать строку, имя класса или интерфейса:
'someModule.someServiceName' => [
'className' => \VendorName\SomeModule\Services\SomeService::class,
],
\VendorName\SomeModule\Contracts\SomeInterface::class => [
'className' => \VendorName\SomeModule\Services\SomeService::class,
],
Регистрация сервиса
Чтобы обратиться к сервису, его нужно зарегистрировать одним из способов.
В Bitrix Framework, файлы .settings.php используются для хранения конфигураций. Они находятся в корне проекта и содержат секции для различных настроек, таких как базы данных, кеширование и сервисы. Service Locator регистрируются в секции services:
/bitrix/.settings.phpreturn [
'services' => [
'value' => [
'someServiceName' => [
'className' => \VendorName\Services\SomeService::class,
],
\VendorName\SomeModule\Contracts\SecondInterface::class => [
'className' => \VendorName\Services\SecondService::class,
'constructorParams' => ['foo', 'bar'],
],
],
'readonly' => true,
],
];
После инициализации ядра сервисы становятся доступны:
$serviceLocator = \Bitrix\Main\DI\ServiceLocator::getInstance();
$someGoodServiceName = $serviceLocator->get('название_service_locator');
$someServiceName = $serviceLocator->get('название_service_locator');
Файл .settings.php в корне модуля описывает сервисы модуля. Это позволяет модулям иметь свои собственные настройки и сервисы, которые не зависят от глобальных настроек:
moduleName/.settings.phpreturn [
'services' => [
'value' => [
'someModule.someServiceName' => [
'className' => \VendorName\SomeModule\Services\SomeService::class,
],
'someModule.someAnotherServiceName' => [
'constructor' => static function () {
return new \VendorName\SomeModule\Services\SecondService('foo', 'bar');
},
],
\VendorName\SomeModule\Contracts\SecondInterface::class => [
'className' => \VendorName\SomeModule\Services\SecondService::class,
'constructorParams' => static function () {
return ['foo', 'bar'];
},
],
],
'readonly' => true,
],
];
Сервисы регистрируются после подключения модуля, используйте префикс имени модуля для уникальности, например disk.urlManager, crm.urlManager.
Регистрация через API осуществляется методами класса /Bitrix/Main/DI/ServiceLocator.
getInstance()получить экземпляр локатораaddInstance(string $code, $service)зарегистрировать экземпляр сервисаaddInstanceLazy(string $code, $configuration)выполнить ленивую регистрацию с конфигурацией, при которой система создаст сервис только при обращении к немуhas(string $code)проверить наличие сервисаget(string $code)получить сервис, метод создает сервис при первом обращении. Если сервиса нет, выбрасывается исключение/Psr/Container/NotFoundExceptionInterface