Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between these two types of constructor injections in php?

I am trying to understand dependency injection in PHP and I see there are two ways to do this in Laravel.

So let us say I have a class Foo like so:

class Foo{

}

Now I have a class called Bar which is dependent on Foo so I could do something like:

class Bar{
    protected $foo;
    public function __construct()
    {
        $this->foo = new Foo();
    }
}

But in Laravel, I have come across terms like typehinting and reflection which allow me to do this:

class Bar{
    protected $foo;
    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
    }
}

What I am trying to understand is the difference between these two. Are they totally identical? And is there a specific reason I should prefer on over the other?

PS: I am newbie and I am not sure if I am using the jargon in the question correctly.

like image 870
Rohan Avatar asked Sep 29 '15 06:09

Rohan


People also ask

What is dependency injection and its types?

A class is no longer responsible for creating the objects it requires, and it does not have to delegate instantiation to a factory object as in the Abstract Factory design pattern. There are three types of dependency injection — constructor injection, method injection, and property injection.

What is dependency injection and how aggregation relationship Fulfils dependency injection?

Dependency injection is way of designing your class so that its dependencies can be provided from outside the class. An aggregate relationship can be modeled to support dependency injection but that does not mean Aggregation and Dependency Injection are the same thing. Save this answer.

How does constructor injection work?

Constructor Injection is the act of statically defining the list of required Dependencies by specifying them as parameters to the class's constructor. The constructor signature is compiled with the type and it's available for all to see.


1 Answers

It mostly comes down to coupling of code.

class Foo {
    public function __construct() {
        new Bar;
    }
}

This couples a very specific Bar to this specific Foo. There's no way to alter which Bar gets instantiated without rewriting this code. This also means Foo needs to know about Bar's dependencies. Maybe today Bar can be instantiated with just new Bar. But maybe tomorrow you're refactoring Bar and must now instantiate it with new Bar($database). Now you also need to rewrite Foo to accommodate that.

That's where dependency injection comes in (the above is not dependency injection, you're not injecting anything):

class Foo {
    public function __construct(Bar $bar) { }
}

This Foo merely declares that it needs an object with the characteristics of Bar upon instantiation. But Foo does not need to know anything about how Bar came about to be, what its dependencies are or what exactly it does. The only thing it expects of Bar is a defined public interface, anything else about it is irrelevant. In fact, to gain even more flexibility, you may want to use an interface instead of a concrete class dependency here.

Dependency injection allows you to divorce concrete details of classes from other code. It allows you to have one central place where classes are instantiated, which is a place where you need to know and consider concrete details about the classes you're instantiating. This can be a dependency injection container for example. You don't want to spread class instantiation logic all over the place, because as mentioned above, that logic may change, and then you need to rewrite code all over the place.

require_once 'Foo.php';
require_once 'Bar.php';

$foo = new Foo(new Bar);

The above code is where it's being decided which Bar gets injected into Foo. It's also the place which needs to worry about Bar's dependencies. Note that dependency loading and instantiation is the only thing this code does. It's trivial to change only this piece of code as necessary, without needing to touch Foo or Bar, which may be full of complex business logic.

Dependency injected code also allows you to take your app apart and put it together flexibly. For example for testing purposes. Or simply to reuse different components flexibly in different contexts.

Also see How Not To Kill Your Testability Using Statics.

like image 100
deceze Avatar answered Sep 18 '22 19:09

deceze