Circular dependency - Injecting objects that are directly depended on each other

人盡茶涼 提交于 2019-12-01 03:38:45

As mentioned on your post on the Dice github ( https://github.com/TomBZombie/Dice/issues/7 ), the only way to resolve without removing the circular dependency is to refactor one of the classes to use setter injection:

class A {
    public $b;

    public function __construct(B $b) {
        $this->b = $b;
    }
}


class B {
    public $a;

    public function setA(A $a) {
        $this->a = $a;
    }
}

This allows the objects to be constructed:

$b = new B();
$a = new A($b);
$b->setA($a);

With the original code:

class A {
    public $b;

    public function __construct(B $b) {
        $this->b = $b;
    }
}

class B {
    public $a;

    public function __construct(A $a) {
        $this->a = $a;
    }
}

You cannot construct it and run into the same problem as the container:

$b = new B(new A(new B(new A(new B(.............))))

The problem with having a container work around this issue using a hack such as ReflectionClass::newInstanceWithoutConstructor is that your objects are now dependent on creation logic which uses this method. You essentially couple the code to the container which is a poor design as your code is now no longer portable and cannot be used without the container to perform the object construction.

Matthieu Napoli

You have a circular dependency, which is very hard to solve. The first thing to do is to try to get rid of this circular dependency by refactoring your classes and how they interact.

If you really can't manage to do it, there are solutions. I'll copy-paste my answer from Self-referencing models cause Maximum function nesting level of x in Laravel 4:

  • Setter injection

Rather than injecting a dependency in the constructor, you can have it injected in a setter, which would be called after the object is constructed. In pseudo-code, that would look like that:

$userRepo = new UserRepository();
$cartRepo = new CartRepository($userRepo);
$userRepo->setCartRepo($userRepo);
  • Lazy injection

I don't know if Dice does support lazy injection, but that's also a solution: the container will inject a proxy object instead of the actual dependency. That proxy-object will load the dependency only when it is accessed, thus removing the need to build the dependency when the constructor is called.

Here is an explanation on how lazy injection works if you are interested: http://php-di.org/doc/lazy-injection.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!