Laravel: Dependency Injection and IoC container

1. What is Dependency Injection?

In short, dependency injection (DI) simply gives an object the objects it depends on (dependencies) from the outside without having to initialize the word in the constructor. This makes the application more flexible and easier to test, because we can easily use Mock class to test.

Try taking a general example not to use the DI technique as follows:

The above example is a symbolic example, but the main problem raised is that the class MyLog is dependent on the StandardLogger class. In other words, the class MyLog is stuck to the StandardLogger class. Currently, when we want to switch to another type of logger (eg FileLogger or MongoDBLogger) we have to revise the constructor of class MyLog.

To solve this dependency problem, we just need to modify the constructor of class MyLog to get a parameter that is a logger. Also called decouple constructs of class MyLog with other classes that depend on it. This is simply called Dependency Injection . Tah-dah, that's too simple, isn't it? So some people say that DI is a 25 dollars name for a concept worth 5 cents. James Shore 's original text:

"Dependency Injection" is a 25-dollar term for a 5-cent concept. […] Dependency injection means giving an object its instance variables. […].

2. What is IoC Conainter?

When applying this DI technique, another problem arises, how do we know which classes this MyLog depends on to initialize it? Creating an instance of the MyLog class is very simple if it only depends directly on another class. However, there is the possibility of nested dependencies, such as MyLog --> DBLogger --> DatabaseAccess . And it makes it very difficult to create an object that we need, because the list of deeply nested dependency classes (deeply nested class dependencies).

To solve this, people think of Dependency Injection Container or Inversion of Control Container (IoC container). The term Inversion of Control is more general than Dependency Injection, from here on, I will be in possession of IoC containers instead of Dependecy Injection Container. In essence, IoC Conainter is a map, or a call center service. It tells us whether a class depends on any other class and resolves those classes by Reflection technique, or from the list registered by the developer.

In fact, saying DI is a new concept, especially in the Java world. Martin Folwer wrote about Dependency Pattern and IoC Container since 2004 . Even further, the inversion of control term has been around since 1988 in Johnson and Foote's Designing Reusable Classes paper. However, until almost full, only a few PHP frameworks use DI and IoC containers like Laravel or Pimple . From Laravel 5.0 onwards Laravel calls it Service container instead of IoC container as before.

Laravel's origin is a IoC Container project for CodeIgniter by Taylor Otwell named CInject. According to Taylor, it is even reused until Laravel 5.x as it is now. And essentially, Laravel is an IoC container, specifically the IlluminateContainerContainer .

"Ảnh chụp màn hình của dự án CInject trên Google Code"

3. How to use IoC containers in Laravel?

– Basic

Try taking a simple example of the two dependent layers of a class.

When we want to initialize an object $car = new Car(); then php will issue an error like this: Argument 1 passed to Car::__construct() must be an instance of Engine, none given,...

It's easy to understand because the Car class depends on the Engine class, which depends on the Piston class. In Laravel, if we use App::make , the IoC container in Laravel will automatically resolve the dependencies of the Car class and help us initialize the $car object properly.

Go back to the example of MyLog above. If we initialize the MyLog object with App::make('MyLog') Laravel will report the following error:

Obviously because our MyLog class takes parameters from constructor is an interface, not a concrete class, Laravel cannot initialize that interface and inject into class MyLog. IoC containers are not smart enough to guess what developers want in this case. So we have to bind LoggerInterface to the specific implementation of that interface.

For example:

– Contextual binding

Sometimes two different classes use the same interface, but they need two different implementations, what to do? Suppose we have added an ExceptionLog class, and we want it to write down the file instead of printing standard ouput like the MyLog class.

Fortunately, Iovel's IoC Container provides Contextual Binding . It helps us bind the interface that a class needs to implement specifically depending on the context.

– Repository pattern

One of the most practical and important applications of IoC containers in Laravel is to remove FAT controller or decouple controllers and business logic code. Controller only serves to coordinate data between view and model.

Consider the following example:

At first glance, the example above looks fine and there is no problem. But it is heavily dependent on the Eloquent model, and everything happens in the controller. This makes the application difficult to test and assuming we want to switch to MongoDB, we have to beat all the rebuilds from scratch.

When using the Repository pattern with IoC containers, we have a more flexible solution. Can easily replace the implementation of MovieRepositoryInterface . You can replace Eloquent with Doctrine or use NoSQL database instead of relational database without changing too much. Just pass the mapping to MovieRepositoryInterface in the AppServiceProvider without caring about what this implementation does specifically as long as it follows the given contract.

4. Conclusion

Dependency Injection and IoC containers are very simple concepts. However, we need to learn to know clearly which DI and IoC are applied. If we apply our code appropriately, it will be less loosely coupled and easier to maintain and test. In addition, in my opinion, IoC containers are the heart of Laravel and also a big difference between Laravel and other PHP frameworks. Moreover, knowing about IoC containers also helps us take advantage and organize Laravel application more reasonably and neatly.

Refer

  1. Inversion of Control Containers and the Dependency Injection pattern http://martinfowler.com/articles/injection.html
  2. Back to basics: OOP, Dependency Injection and Cake Pattern http://kipalog.com/posts/Tro-lai-voi-co-ban-OOP–Dependency-Injection-va-Cake-Pattern
  3. Dependency Injection Demystified http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html
  4. Laravel – Lessons Learned— php [world] 2015 – Taylor Otwell https://www.youtube.com/watch?v=xKefsl_UiM0
  5. Service Container – Laravel Official Website https://laravel.com/docs/5.2/container#contextual-binding

ITZone via butchiso

Share the news now