Сервисы приложение удобно внедрять для организации повторно используемого кода, когда некий функционал описывается в виде некого класса, объект которого во время жизни приложения обычно создается единажды, может включать определенные параметры. Подробнее об использовании Сервис-ориентированой архитектуры
Доступ к сервису осуществлется при помощи метода модуля \WS\Tools\Module::getService($name)
, $name
- имя сервиса.
В следующем примере будет получен доступ к сервису логирования через файл.
<?php
CModule::IncludeModule('ws.tools');
$module = \WS\Tools\Module::getInstance();
$fileLog = $module->getService('myFileLog');
$fileLog->put('error message');
Сервис можно определить двумя способами:
- Указание сервиса с параметрами и зависимостями в настройке
- Динамическое определение сервиса
В общей конфигурации модуля сервисы определяются параметрами с ключом services
.
Параметры определения сервисов состоят из ассоциативного массива, где ключи - имена сервисов, значения - параметры инициализации сервисов.
Параметры инициализации сервисов сосоят из:
class
- имя класса сервисаparams
- параметры используемые сервисом, будут внедрены при инициализацииdepends
- зависимости от других сервисов
При динамическом определении сервиса необходимо получить объект ServiceLocator
:
<?php
CModule::IncludeModule('ws.tools');
$module = \WS\Tools\Module::getInstance();
$serviceLocator = $module->getServiceLocator();
$serviceLocator->set('myFileLog', array(
'class' => 'LogToFile',
'path' => __DIR__.'/dump.log',
''
), array('user'));
Определим некий класс, который будем использовать в качестве сервиса:
<?php
class LogToFile {
/**
* Имеется необходимость использовать класс CurrentUser
* @var CurrentUser
**/
protected $user;
private $_path;
public function __construct($path) {
$this->_path = $path;
}
public function put($content) {
file_get_contents($this->_path, array(time(), $this->user->name, $content));
}
}
Конфигурация с использованием класса:
<?php
$config = array(
// установка сервисов с параметрами и зависимостями
'services'=> array(
'myFileLog' => array(
'class' => 'LogToFile',
'params' => array(
'path' => __DIR__.'/dump.log'
),
'depends' => array('user')
),
'user' => array(
'class' => 'CurrentUser'
)
)
);
CModule::IncludeModule('ws.tools');
$module = \WS\Tools\Module::getInstance();
$module->config($config);
Работа с сервисом в приложении:
<?php
$fileLog = $module->getService('myFileLog');
$fileLog->put('error message');
Работа с объектом ServiceLocator
напрямую нужно использовать в основном для инициализации объектов-сирот, т.е. те объекты
которые не будут доступны при последующих вызовов получения сервисов.
Получение объекта осуществляется ServiceLocator
следующим образом:
<?php
$serviceLocator = $module->getServiceLocator();
$log = $serviceLocator->createInstance('log');
Методы объекта:
set($name, $params = array(), $depends = array())
- динамическая установка параметров инициализации$params
сервиса $name с зависимостями от сервисов$depends
.get($name)
- получение сервиса$name
willUse($name, $object)
- установка объекта$object
для дальнейшего использования в качестве сервиса$name
createInstance($name, $params = array(), $depends = array())
- создание экземплара объекта с использованием параметров и зависимостей. Объект не будет зарегистрирован вServiceLocator
для дальнешего использования. Но он может пльзоватся параметрами конфигурации при инициализации.
Внедрение зависимостей являеются общим паттерном программирования который повышает уровень слабой связанности объектов приложения, облегчает замену компонентов и упрощает рефакторинг кода. Подробнее о пользе внедрения зависимостей можно прочитать в статье.
При инициализации объекта ServiceLocator
будет его наполнять параметрами и зависимыми сервисами по следующим признакам:
- При совпадении имени параметра или сервиса в конструкторе класса
- При совпадении класса сервиса в определении параметра конструктора класса
- При совпадении свойств класса. Свойства должны быть
protected
илиpublic
. Вprivate
свойства параметры не передаются
Пример конфигурации для инициализации параметров:
<?php
// параметры для сервисов
$config = array(
'services' => array(
'db' => array(
'class' => 'DateBase',
'params' => array(
'host' => 'localhost',
'user' => 'user',
),
'depends' => array('shell')
),
'shell' => array(
'class' => 'CommandLineShell',
'params' => array(
'rootDir' => __DIR__.'/../root'
)
)
)
);
// классы сервисов
class DateBase {
/**
* В это свойство будет записан объект CommandLineShell
* @var CommandLineShell
**/
protected $shell;
/**
* В приватные свойства параметры не записываются
**/
private $connectionParams;
public function __construct($host, $user) {
$this->_connectionParams = array(
'host' => $host,
'user' => $user
);
}
/**
* Будет проинициализированно Shell объектом
**/
public function getShell() {
return $this->shell;
}
}
class CommandLineShell {
/**
* При инициализации наполнится параметром сомостоятельно
**/
protected $rootDir;
public function getRootDir() {
return $this->rootDir;
}
}
CModule::IncludeModule('ws.tools');
$module = \WS\Tools\Module::getInstance();
$module->config($config);
/* @var DateBase */
$db = $module->getService('db');
$db->getShell()->getRootDir(); // /var/www/project/local/root
Из примера выше видно, что сервисы инициализируются автоматически с зараниее указанными параметрами.