Laravel4 IOC container benefits

I find it difficult to understand the benefits of an IOC container in the area of ​​dependency injection.
Given this basic example:

App::bind('Car', function() { return new Car; }); Route::get('/', function() { dd(App::make('Car')); // resolve it }); 

I do not see the benefits of using the IOC container over creating a new instance in the constructor.
Besides the benefits of testing, I read that the reason is that it is a loose connection.
However, since the “car” binding simply returns an instance of a new car, I don’t see in what sense this example will be more loosely coupled.
For me they seem to be doing the same thing.

+6
source share
2 answers

You are right, in far-fetched examples it is usually difficult to understand what benefit you get. Consider an example level controller: the real world:

 class TestController { public function __construct(CarRepositoryInterface $car) { $this->_repository = $car; } public function route($id) { return View::make('my.view')->with('car', $this->_repository->find($id)); } } 

Very simple, the repository is entered into the constructor of the controller, which is then used on the route to load a specific car by id. The details of the repository here are not so important and, presumably, there is a service provider linking CarRepositoryInterface with a specific implementation of CarRepository :

 class RepositoryServiceProvider extends ServiceProvider { public function register() { $this->app->bind('CarRepositoryInterface', function($app) { return new EloquentCarRepository(new Car()); }); } } 

So, every time a controller is created, an EloquentCarRepository is created and inserted into the constructor for use by the controller.

But wait, what happens if you want to switch from using Eloquent to say Doctrine? Since we use dependency injection here, you do not need to change one line of code in your controller (or any other controller that can use your current implementation). All you have to do is define another implementation of CarRepositoryInterface , say DoctrineCarRepository , and change one line of code from the service provider:

 return new DoctrineCarRepository(); 

Everything else that depends on CarRepositoryInterface now works magically. And all this thanks to IoC.

You can also add more complex logic to your service provider:

 public function register() { $this->app->bind('CarRepositoryInterface', function($app) { if($app->environment() == 'production') { return new EloquentCarRepository(new Car()); } else { return new DoctrineCarRepository(new Car()); } }); } 

Here, EloquentCarRepository will only be used in the production environment, while in any other environment the DoctrineCarRepository will be used. (This example shows how you can get a lot more control over what type of object is created at runtime, rather than what I'm protecting from this.)

Adding

As I said in my comment, this is a type of use in which you are not quite sure which type of object you will need before execution. There is another use: Depedency Management.

Suppose you have an object that depends on another object:

 class MyObject { public function __construct(AnotherObject $obj) { $this->obj = $obj; } } 

Assume also that AnotherObject depends on another object:

 class AnotherObject { public function __construct(YetAnotherObject $obj) { $this->obj = $obj; } } 

This can quickly get out of hand, and you can end up with long chains of dependencies that must be satisfied before you can actually create an object. With IoC, you can simply snatch an instance from a container:

 $myObject = app()->make('MyObject'); 

As long as IoC can create all the dependencies, you do not need to do something like this:

 $yetAnotherObj = new YetAnotherObject(); $anotherObj = new AnotherObject($yetAnotherObj); $myObject = new MyObject($anotherObj); 
+5
source

This example you post is not a real use case for an IoC container ...

The IoC container is more useful in this example:

If you have a BillingNotifierInterface that is implemented using EmailBillingNotifier

 App::bind('BillingNotifierInterface', function() { return new EmailBillingNotifier; }); 

And BillerInterface used, which is implemented using StripeBiller , for example:

 App::bind('BillerInterface', function() { return new StripeBiller(App::make('BillingNotifierInterface')); }) 

But all of a sudden, your team wants to change from EmailBillingNotifier to SMSBillingNotifier , you just change 1 line and your application continues to work like a cat ...

 App::bind('BillingNotifierInterface', function() { return new SMSBillingNotifier; }); 

This app is REAL IoC CONTAINER ...

+3
source

Source: https://habr.com/ru/post/973662/


All Articles