Следом ещё одна заметка о Symfony 3.4 и мучениях при работе с его сервис-контейнером. Допустим, есть задача проинтегрировать в приложение библиотеку от стороннего разработчика. Архитектура библиотеки конечно не внушает доверия и просить автора привести её в порядок — бесполезно. Иначе говоря, нужно через Service Container Symfony работать с библиотекой, автор которой нарушил максимальное количество принципов объектно-ориентированного программирования и проектирования.

Например, в некой библиотеке имеется один единственный класс через который происходит работа. Однако, в некоторых случаях нужно вызывать методы объекта являющегося свойством «главного» класса, например:

$Object->part->call($args);

Нет, можно конечно прокидывать родительский объект во все части приложения, но это не гибко и не всегда удобно, т.к. некий объект получает доступ ко всему родительскому объекту и может сильно повлиять на его состояние.

В Laravel такие вещи делаются элементарно просто:

$this->app->bind(SomeInterface::class, function($app) {
 return $app[Object::class]->part;
});

Но в Symfony ничего подобного нет! Приходится выкручиваться так:

$expr = new \Symfony\Component\ExpressionLanguage\Expression("service('MyBundle\\\\Object').part");

$container->autowire(\MyBundle\SomeInterface::class)
    ->setArguments(['$part' => $expr]);

Обратите внимание на четыре слэша, именно такая последовательность символов служит разделителем неймспейсных директорий. А вместо привычного -> свойство объекта нужно извлекать через точку. После чего полученный экспрешен можно использовать аналогично референсу.

Умные люди говорят что есть и другое более красивое решение: создать фабрику, которая бы возвращала объект из свойства другого объекта. Но на мой взгляд это ещё более сложное решение для такой банальной задачи.


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *