В Symfony появился Service Locator

Обсуждаем, как правильно строить приложения
Ответить
Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

В Symfony появился Service Locator

Сообщение samdark » 2017.05.04, 16:02

http://symfony.com/blog/new-in-symfony- ... e-locators

Что думаете? Мода в очередной раз меняется?

https://www.youtube.com/watch?v=Ks75ep-Ztdg

Аватара пользователя
ElisDN
Сообщения: 5468
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение ElisDN » 2017.05.04, 20:27

Так такой однозначный резолв хэндлеров для команд всегда реализовывался инъекцией самого контейнера и дёрганием его как локатора:

Код: Выделить всё

$handler = $this->container->get('app.handler.' . $commandName);
чтобы не инстанцировать по тегам сотни хэндлеров через CompillerPass при извлечении шины.

А более продвинутые программисты спокойно делали SFHandlerResolver implements HandlerResolverInterface для сторонних библиотек вроде SimpleBus, чтобы использовать new SFHandlerResolver($container, $map), реализующий метод resolve:

Код: Выделить всё

$handler = $this->handlerResolver->resolve($command);
который внутри себя уже делал:

Код: Выделить всё

public function resolve($command) {
    return $this->container->get($this->map[get_class($command)]);
}
или:

Код: Выделить всё

return $this->container->get($this->prefix . '.' . get_class($command));
Но нерадивые программисты по примеру Yii (или нечаянно) могли так из него не только обработчики дёрнуть, но и любой другой сервис из контейнера достать.

Чтобы такие резолверы с префиксами для своих маппингов не писать (хардкод) и чтобы весь основной контейнер не инъектить (риск говнокода) там придумали возможность создать лёгкую прокси-копию контейнера, в которую можно передать только нужный список сервисов из основного контейнера по новым именам:

Код: Выделить всё

services:
    app.command_handler_locator:
        class: Symfony\Component\DependencyInjection\ServiceLocator
        tags: ['container.service_locator']
        arguments:
            -
                AppBundle\FooCommand: '@app.command_handler.foo'
                AppBundle\BarCommand: '@app.command_handler.bar'
и инъектить уже этот безопасный контейнер-песочницу вместо основного и из него по новым ключам дёргать только его содержимое:

Код: Выделить всё

$handler = $this->handlerLocator->get($commandName);
Такой хитрый вспомогательный объект и назвали здесь именем ServiceLocator.

И от утечки глобального доступа ко всей куче сервисов защитились, и проблему резолва по простым ключам без префиксов решили, и основной контейнер как локатор теперь можно в шинах не использовать.

Про это и говорится в описании.
samdark писал(а):
2017.05.04, 16:02
Что думаете? Мода в очередной раз меняется?
Нет, это не про "тот самый" ServiceLocator.

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.04, 21:37

Ну как не тот самый, когда тот? Если контейнер инъектится, он автоматически превращается в локатор.

Аватара пользователя
ElisDN
Сообщения: 5468
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение ElisDN » 2017.05.04, 21:54

samdark писал(а):
2017.05.04, 21:37
Ну как не тот самый, когда тот? Если контейнер инъектится, он автоматически превращается в локатор.
Ну так "автоматически" он там и был всегда. Что изменилось?

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.04, 22:01

Явно назвали локатор локатором и по сути поощрили явную зависимость от него.

Аватара пользователя
ElisDN
Сообщения: 5468
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение ElisDN » 2017.05.04, 22:20

samdark писал(а):
2017.05.04, 22:01
Явно назвали локатор локатором и по сути поощрили явную зависимость от него.
Поощрили для единственного примера-исключения с CommandBus, где использование контейнера как локатора для runtime-получения объекта обработчика по имени команды было необходимо. Сделали возможность создания по требованию легковесных отдельных локаторов-коллекций для группировки однородного белого списка обработчиков для шин, чтобы не использовать не по назначению оригинальный контейнер. Больше никаких кейсов для использования контейнера как локатора в приложении не вижу.

Этот ServiceLocator в Symfony - именно вещь для организации коллекций однородных объектов с доступом по индексу вроде:

Код: Выделить всё

$handler = $handlerLocator->get($commandName);
$db = $dbLocator->get($connectionId);
а не глобальная куча сервисов.
Последний раз редактировалось ElisDN 2017.05.05, 07:47, всего редактировалось 2 раза.

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.04, 22:34

Ну не знаю... я прокидывание контейнера в том или ином случае встречал в каждом проекте на Symfony, с которым приходилось работать.

Аватара пользователя
ElisDN
Сообщения: 5468
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение ElisDN » 2017.05.04, 22:51

samdark писал(а):
2017.05.04, 22:34
Ну не знаю... я прокидывание контейнера в том или ином случае встречал в каждом проекте на Symfony, с которым приходилось работать.
Это реально необходимо только в Twig_Extension для получения $this->container->get('templating.helper.assets'), чтобы не зациклить граф. Хотя это решается прокидыванием Lazy Load Proxy. В остальных случаях прокидывание не особо нужно.
Последний раз редактировалось ElisDN 2019.03.18, 13:11, всего редактировалось 2 раза.

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.04, 23:56

Да я-то понимаю, что прокидывание само по себе убивает всю идею DI, но что есть то есть...

anton_z
Сообщения: 457
Зарегистрирован: 2017.01.15, 15:01

Re: В Symfony появился Service Locator

Сообщение anton_z » 2017.05.05, 03:17

Плохие архитектурные решения в симфони есть (стандартный DiC, например) как и везде, но локатор, описанный в заметке к ним не относится.

Заметка показывает, как можно удобно использовать psr-11 для создания шины. DI это не убивает - командная шина сама по себе локатор обработчиков и то что туда заинжектили пср контейнер да еще со списком команд, это правильное использование контейнера.

Почему нельзя инжектить контейнер:
1. Зависимость от контейнера.
2. Неявная зависимость от всех сервисов, имеющихся в контейнере - не поймешь по API класса, что он использует. Программирование по контракту сломано.

Принятие psr-11 фактически сняло первую проблему - зависеть от тоненького psr интерфейса не страшно, а наоборот - есть куча реализаций, и адаптеры писать не надо, как на свои интерфейсы.
Вторая проблема в представленном кейсе не имеет смысла - шина все равно зависит от всех обработчиков и команд. Так что DI здесь не нарушен и SL здесь не антипаттерн. Все разумно.

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.05, 11:49

PSR-11 проблему явной зависимости от контейнера не снял ни в коем случае. Как была, так и осталась. Он вообще для того, чтобы можно было подменять реализацию контейнера, а не для чего-то ещё.

По второму пункту на тему частного случая согласен, но ведь все мы знаем, что примеры из документации применяют по поводу и без...

anton_z
Сообщения: 457
Зарегистрирован: 2017.01.15, 15:01

Re: В Symfony появился Service Locator

Сообщение anton_z » 2017.05.05, 14:43

samdark писал(а):
2017.05.05, 11:49
PSR-11 проблему явной зависимости от контейнера не снял ни в коем случае. Как была, так и осталась. Он вообще для того, чтобы можно было подменять реализацию контейнера, а не для чего-то ещё.
Как раз он снял эту проблему. Принцип инверсии зависимостей говорит, что мы должны зависеть от абстракций. ContainerInterface - абстракция, делающая зависимость от реализации контейнера неявной.

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.05, 17:19

Именно что мы должны зависеть от абстракций. То есть на вход требовать конкретные интерфейсы, а не контейнер, из которого можно достать что угодно.

Аватара пользователя
slavcodev
Сообщения: 3133
Зарегистрирован: 2009.04.02, 21:42
Откуда: Altea, Spain
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение slavcodev » 2017.05.05, 18:16

Саша, а как же "Фреймворк дает возможности, как их применят на совести программиста"? :D
Жду Yii 3!

Аватара пользователя
samdark
Администратор
Сообщения: 9251
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: В Symfony появился Service Locator

Сообщение samdark » 2017.05.05, 19:11

Я за то, чтобы фреймворк давал осознанно срезать углы. Просто раньше Symfony ставил более жёсткие рамки и его за это хвалили, а тут, получается, рамки расширяются.

Ответить