Руслан Ханов, «Контейнер сервисов — Что? Где? Когда?»
TRANSCRIPT
Полезные ссылки● https://yugeon-dev.blogspot.ru/2010/07/inversion-of-control-containers-and_21.html
● https://symfony.com/doc/current/book/service_container.html
● https://habrahabr.ru/post/278049/
2
SOLID
Первые пять принципов OOAD
Объектно-ориентированный анализ и проектирование
3
Dependency inversion principle
Принцип инверсии зависимостей
4
Реализация
● Фабричный метод (Factory method)
● Локатор сервисов (Service locator)
● Внедрение зависимости (Dependency injection)
5
Фабричный метод
6
7
# Factory.php
class Factory{ public function getRepository() { return new Repository(); }}
# Controller.php
class Controller{ public function executeAction() { $factory = new Factory(); $repository = $factory->getRepository(); # do some action ... }}
Локатор сервисов
8
9
# ServiceLocator.php
class ServiceLocator{ public function get($name) { return $this->services[$name]; }}
# Controller.php
class Controller{ public function executeAction() { $repository = $this->serviceLocator->get(‘repository’); # do some action ... }}
Внедрение зависимости
10
11
# Controller.php
class Controller{ # dependency injection … public function executeAction() { $repository = $this->repository; # do some action ... }}
Реализация (для закрепления)
● Фабричный метод (Factory method)
● Локатор сервисов (Service locator)
● Внедрение зависимостей (Dependency injection)
12
Плюсы
13
Плюсы
● Гибкость
14
Плюсы
● Гибкость● Тестируемость
15
Плюсы
● Гибкость● Тестируемость● Немногословность (no boilerplate code)
16
Минусы
17
Минусы
● “Размазанная” логика
18
Минусы
● “Размазанная” логика● Использование общего состояния (Doctrine index)
19
Минусы
● “Размазанная” логика● Использование общего состояния (Doctrine index)
● Переусложнение
20
Реализация в symfony
Внедрение зависимостей
21
Реализация в symfony
Внедрение зависимостей
Контейнер сервисов (Service container)
22
Контейнер сервисов
● Сервисы● Контейнер
23
Типы внедрения
24
● Через конструктор● Через вызов метода● Через свойство
24
Через конструктор
25
26
# Controller.php
class Controller{ public function __construct(Repository $repository) { $this->repository = $repository; }
public function executeAction() { $repository = $this->repository; # do some action ... }}
# services.yml
services: repository: class: Repository controller: class: Controller arguments: - “@repository”
Через вызов метода
27
28
# Controller.php
class Controller{ public function setRepository(Repository $repository) { $this->repository = $repository; }
public function executeAction() { $repository = $this->repository; # do some action ... }}
# services.yml
services: repository: class: Repository controller: class: Controller calls: - [setRepository, [“@repository”]]
Через свойство
29
30
# Controller.php
class Controller{ /** * @var Repository */ public $repository;
public function executeAction() { $repository = $this->repository; # do some action ... }}
# services.yml
services: repository: class: Repository controller: class: Controller properties: repository: “@repository”
Типы внедрения (для закрепления)
● Через конструктор● Через вызов метода● Через свойство
31
Примеры внедрения
● Controller
● Repository
● Form & FormType
● Command
● Lots of services!
32
33
# Controller.php
class Controller{ public function executeAction() { # do some action ... }}
# services.yml
services: controller: class: Controller
34
# Repository.php
class Repository{ public function find($id) { # find entity ... }}
# services.yml
services: repository: class: Repository factory: - “@doctrine.orm.default_entity_manager” - getRepository
35
# FormType.php
class FormType{ public function buildForm(FormBuilderInterface $builder, array $options) { # build form ... }}
# services.yml
services: form_type: class: FormType tags: - {name: form.type, alias: form_type} form: class: Symfony\Component\Form\Form factory: - “@form.factory” - create arguments: - form_type
36
# Command.php
class Command{ protected function execute(InputInterface $input, OutputInterface $output) { # execute command ... }}
# services.yml
services: repository: class: Command tags: - {name: console.command}
37
# lots-of-services.yml
services: validator: class: Validator serializer: class: Serializer client: class: Client storage: class: Storage translator: class: Translator
Антипаттерны
● Использование service locator (вне инфраструктурного
кода)
● Использование micro service locator
● Семантическая конфигурация
38
Service locator
39
40
# Controller.php
class Controller{ public function setContainer(ContainerInterface $container) { $this->container = $container; }
public function executeAction() { $repository = $this->container->get(‘repository’); # do some action ... }}
# services.yml
services: repository: class: Repository controller: class: Controller calls: - [setContainer, [“@service_container”]]
Micro service locator
41
42
# Controller.php
class Controller{ public function setFormFactory(FormFactory $formFactory) { $this->formFactory = $formFactory; } public function executePostAction() { $formPost = $this->formFactory->create(‘form_type_post’); # do post action ... } public function executePutAction() { $formPut = $this->formFactory->create(‘form_type_put’); # do put action ... }}
# services.yml
services: controller: class: Controller calls: - [setFormFactory, [“@form.factory”]]
Семантическая конфигурация
43
44
# CompilerPass.php
class CompilerPass extends CompilerPassInterface{ public function process(ContainerBuilder $containerBuilder) { $definition = $container->getDefinition(‘service’);
$definition->setLazy(true); }}
# services.yml
services: service: class: Service # lazy: true
# CompilerPass.php
class CompilerPass extends CompilerPassInterface{ public function process(ContainerBuilder $containerBuilder) { $parameters = $container->getParameter(‘vendor’);
foreach ($parameters as $key => $value) { $container->setParameter(‘vendor_’ . $key, $value);
} }}
# services.yml
parameters: vendor: key_1: value_1 key_2: value_2services: service: class: Service arguments: - “%vendor_key_1%” - “%vendor_key_2%”
45
Антипаттерны (для закрепления)
● Использование service locator (вне инфраструктурного
кода)
● Использование micro service locator
● Семантическая конфигурация
46
Плюсы (для закрепления)
● Гибкость● Тестируемость● Немногословность (no boilerplate code)
47
Заключение
● Многое становится проще● Есть несколько реализаций● Если не читать документацию, можно “заиграться”
● Можно самостоятельно реализовать
48
Спасибо за внимание!
https://github.com/hanovruslan
49