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