Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have used Dice PHP DI container for quite a while and it seems the best in terms of simplicity of injecting dependencies.

From Dice Documentation:

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

class B {
    
}

$dice = new \Dice\Dice;    
$a = $dice->create('A');
var_dump($a->b); //B object

However, when you have to use objects that are directly dependent on each other, the finall result is server error, because of the infinite loop.

Example:

class A {
    public $b;

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

class B {
    public $a;

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

Author of Dice says that there is no way to construct an object from the A or B classes. As:

  • An 'A' object requires a 'B' object to exist before it can be created
  • But a 'B' object requires an 'A' object to exist before it can be created

Author says, that this limitation concerns all DI containers!


Question:

What would be the best solution for overcoming this problem nicely without changing initial code? Could anyone provide an example of using other DI containers, when it would be possible to run exampled code without bulky workarounds?

like image 244
Ilia Avatar asked Jun 06 '14 07:06

Ilia


People also ask

What is circular dependency in dependency injection?

A cyclic dependency exists when a dependency of a service directly or indirectly depends on the service itself. For example, if UserService depends on EmployeeService , which also depends on UserService . Angular will have to instantiate EmployeeService to create UserService , which depends on UserService , itself.

How do I fix circular dependency error?

To resolve circular dependencies: Then there are three strategies you can use: Look for small pieces of code that can be moved from one project to the other. Look for code that both libraries depend on and move that code into a new shared library. Combine projectA and projectB into one library.

What is circular dependency injection How do you resolve it explain with an example?

Circular dependency in Spring happens when two or more beans require instance of each other through constructor dependency injections. For example: There is a ClassA that requires an instance of ClassB through constructor injection and ClassB requires an instance of class A through constructor injection.

How can we avoid circular dependency between modules?

Avoiding circular dependencies by refactoringCircular dependencies create tight couplings between the classes or modules involved, which means both classes or modules have to be recompiled every time either of them is changed.


1 Answers

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

like image 57
Matthieu Napoli Avatar answered Sep 20 '22 13:09

Matthieu Napoli