Избегать циклических ссылок при внедрении зависимостей Symfony2?

Я большой поклонник внедрения зависимостей, но что-то меня беспокоит, и мне было интересно, может ли кто-нибудь дать мне объяснение:

Невозможно создать две службы, которые зависят друг от друга, потому что мы получим исключение «Циклическая ссылка». Я думаю, что все, кто использует symfony2, сталкивались с этой ошибкой.

Хотя я очень хорошо понимаю эту ошибку, я иногда сталкиваюсь с ней, потому что с большим количеством сервисов возникает сложность... и, возможно, также потому, что проектирование/оценка сервисов непросты.

Поэтому мне было интересно узнать об основной причине этой ошибки:

  1. Это для того, чтобы защитить нас от потенциальной серьезной ошибки проектирования? Если это так, не могли бы вы привести пример того, что серьезного может произойти, если две зависимые службы могут «жить вместе»?
  2. Это чисто техническое? т.е. потому что невозможно вызвать оба конструктора. Если это основная причина, почему бы не решить ее, заставив конструкторы служб быть пустыми и иметь метод инициализации?

I.e.:

class MyService1{

   private $service2;

   public function __construct(){ //empty constructor
      ...
   }

   protected function init(MyService2 $service2, ...){
      $this->service2 = $service2;
   }

}

class MyService2{

   private $service1;

   public function __construct(){ //empty constructor
      ...
   }

   protected function init(MyService1 $service1, ...){
      $this->service1 = $service1;
   }

}

А затем создайте экземпляры обеих служб:

$service1 = new MyService1();
$service2 = new MyService2();
$service1->init($service2);
$service2->init($service1);

Я почти уверен, что есть что-то, чего я не понял в глубине. Так может ли кто-нибудь объяснить мне, почему нам не позволяют создавать циклические ссылки в контейнере?

Спасибо


person Vincent Pazeller    schedule 14.12.2015    source источник
comment
Потому что ваш метод service1-›init получит службу, которая не полностью инициализирована. Плохие вещи произойдут, когда вы попытаетесь использовать частично инициализированный сервис.   -  person Cerad    schedule 14.12.2015
comment
Извините, меня не убеждает этот аргумент. Потому что в методе init вы будете в том же состоянии, что и в конструкторе... Разработчики Symfony2 могут создать абстрактный класс Service, который заставит реализовать этот метод... Я не думаю, что это особенно опасно.   -  person Vincent Pazeller    schedule 14.12.2015
comment
Так что же произойдет, если a зависит от b, которое зависит от c, которое, в свою очередь, зависит как от a, так и от b? Я подозреваю, что после того, как вы немного поработаете с Ди, ваше мнение может измениться. Если нет, то отправьте патч. Группа Symfony поощряет помощь извне.   -  person Cerad    schedule 14.12.2015
comment
Я не думаю, что это очень сложно реализовать в общем случае. Но я думаю, что есть и другая причина, по которой это не было сделано. И это, вероятно, скорее причина передовой практики, чем техническая. И поэтому я спрашиваю здесь... чтобы лучше понять...   -  person Vincent Pazeller    schedule 14.12.2015


Ответы (1)


В идеале ваши службы должны придерживаться принципа инверсии зависимостей.

То есть компоненты высокого уровня будут зависеть от компонентов низкого уровня, но не наоборот. Кроме того, для большей согласованности эта зависимость будет осуществляться через абстракцию или интерфейс.

См. этот вопрос от Programmers SE сайт.

введите здесь описание изображения

person Adam Elsodaney    schedule 14.12.2015
comment
Думаю, я понял это. Но я думаю, что даже если прототипом конструктора Компонента A является __construct(ComponentBInterface $componentB), конфигурация службы Symfony2 внедрит реализацию ComponentB. В вашей диаграмме нет проблем, потому что она проста. Позвольте мне привести конкретный пример: у меня есть BasketHelper, который содержит методы, связанные с заказами, и CertificateHelper (который обрабатывает продукт сертификата). Есть некоторые методы, которые находятся где-то посередине (т. е. связаны как с заказами, так и с сертификатами)... Тогда, я думаю, мне следует создать третью службу, которая зависит от обоих? - person Vincent Pazeller; 14.12.2015