Dependency Injection and control inversion
Dependency Injection When I first touched the word, I was somewhat confused, so far I am also confused, so today we will explore the laravel in the dependency injection (Dependency injection), to understand it well. control reversal The first impression is a good abstruse noun ... Looks like a reverse control? Don't understand? Then straighten it out!
Starting point
What is dependency
I can not live without you, then, you are my dependence. To be blunt:
is not my own, but I need, are all I rely on. All that needs to be externally provided is the need for dependency injection.
We use the code to describe:
Class Boy { protected $girl; Public function __construct (Girl $girl) { $this->girl = $girl; }} Class Girl { ...} $boy = new Boy (); Error; Boy must had girlfriend!//so had to give him a girlfriend $girl = new Girl (); $boy = new ($girl); right! So happy!
From the above code we can see that boy strong dependent girl must be injected into the girl instance at the time of construction.
So why should there be a dependency injection concept, and what does dependency injection solve?
Let's fix the code that we wrote in our Beginner's code:
Class Boy { protected $girl; Public Function __construct () { $this->girl = new Girl ();} }
How is this different from the previous approach?
We'll find that boy's girlfriend is hard coded into boy's body. Every time a boy is reborn, he wants to be a different type of girlfriend to strip himself off. (⊙o⊙) ...
One day boy especially like a loligirl, very want her to be her own girlfriend ... What to do? Rebirth yourself ... Clawed himself ... Throw the girl. Tuck the Loligirl in.
Class Loligirl {}class boy { protected $girl; Public Function __construct () { // $this->girl = new Girl (); Sorry ... $this->girl = new Loligirl ();} }
One day boy has a crush on be. (⊙o⊙) ... Boy is so annoying ...
Don't you feel so good? Every time I meet the person who is sincere to torture themselves so ...
Boy said, I'm going to be a little stronger. I don't want to be changed!
Well, let's make boy strong:
Interface Girl { //boy need knows that I had some abilities.} Class Loligril implement Girl { //I'll implement Girl ' s abilities.} Class Vixen implement Girl { //Vixen definitely is a Girl, does not doubt it.} Class Boy { protected $girl; Public function __construct (Girl $girl) { $this->girl = $girl; }} $loliGirl = new Loligirl (), $vixen = new Vixen (), $boy = new Boy ($loliGirl), $boy = new Boy ($vixen);
Boy was so happy that he could finally experience a different life without having to clawed himself ... So happy!
Summary
Because most applications implement business logic by cooperating with each other by two or more classes, each object needs to get a reference to the object it is working with (that is, the object it depends on). If this acquisition process is implemented on its own, it will result in highly coupled code and difficult to maintain and debug.
So there is the concept of dependency injection, which solves the following problems:
- Decoupling between dependencies
- Unit test for easy mock
= = The previous dependency injection actually requires us to manually inject dependency, as programmers how can we tolerate this inefficient injection method, well, let's start by understanding the IOC concept.
Control inversion (inversion of control, IOC)
control inversion is a design principle in object-oriented programming, which can be used to reduce the coupling degree between computer code. The most common of these is called Dependency injection (Dependency injection, DI), and a "dependency lookup" (Dependency lookup). By controlling the inversion, the object is created by an external entity that regulates all objects within the system, passing a reference to the object on which it depends. It can also be said that the dependency is injected into the object.
In other words, we need a control system in which we store some objects in the entity, or the description of the object, and when the object is created, pass the reference of the object that the object depends on. In Laravel service container is this efficient control system, it is the core of Laravel. Let's take a look at how Laravel implements automatic dependency injection.
Dependency Injection in the Laravel
Now let's look at the examples of the documentation that should not be difficult to understand:
Mailer = $mailer; } /** * Purchase a podcast. * * @return void * /Public Function handle () { // }}
In this example, the Purchasepodcast job needs to send e-mails if a podcast is purchased. So, we'llinject a service that's able to send e-mails. Since The service is injected, we were able to easily swaps it out with another implementation. We is also able to easily "mock", or create a dummy implementation of the mailer when testing our application.
When it comes to dependency injection in laravel, we have to understand Laravel's service Container
Services container (service Container)
The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this:class dependencies was "injected" into the class via T He constructor or, in some cases, "setter" methods.
From the introduction is not difficult to see the service container is the control of the reversal of the container, it is said before the dispatch system. The way to implement dependency injection can be in a constructor or setter method.
If we look at service container we will find that the Laravel service container only stores the description of the object, and does not need to know how to construct an object specifically, because it will automatically parse an object according to the PHP reflection service.
Reflection
In computer science, reflection refers to the ability of a computer to access, detect, and modify its own state or behavior at runtime (run time). It is used as a metaphor to say that programs can "observe" and modify their behavior.
Languages that support reflection provide runtime features that are difficult to implement in low-level languages. These features include
- Discover and modify the structure of the source code (such as code blocks, classes, methods, protocols, and so on) as a first class object.
- Converts a call or reference that matches a class or function to a class or function.
- Computes a string at run time as if it were a source code statement.
- Create a new language bytecode interpreter to give the programming structure a new meaning or use.
The reflection of the PHP implementation can be viewed in the official website document: Reflection API
Example
$reflector = new Reflectionclass (' App\user '), if ($reflector->isinstantiable ()) { $user = $refector Newinstance (); In the other case can send any arguments}
The build method of the Laravel service container needs to parse the dependencies through the reflection service, for example, what are the dependent parameters that need to be passed in the construct function? It will need to use the following methods:
$constructor = $reflector->getconstructor (); If There is no constructors, that means there is no dependencies then //We can just resolve the instances of the Objects right away, without //resolving any other types or dependencies out of these containers. if (Is_null ($constructor)) { Array_pop ($this->buildstack); return new $concrete; } $dependencies = $constructor->getparameters ();
Now should we have a little idea about how laravel can implement dependency auto-injection? To sort out the questions:
- How do I implement automatic injection of dependencies? (Control inversion, use reflection)
- What does dependency injection need? (Organize dependencies [construct | setter] and also parse dependent pass-through references)
- How to parse dependencies?
You may ask why you ask how to resolve dependencies? The analytic dependence must be used to reflect, reflection, you know the class name can not be directly resolved it?
In fact... That's not true... (@ο@)
Many times in order to improve the extensibility and maintainability of code, when writing a class depends on the interface or abstract class, rather than a specific implementation class. Do you understand? This dependency is definitely wrong if it resolves to an interface or abstract class and then uses reflection.
Then we need to inject the relevant dependency mapping in the dispatch system, and then parse the relationship correctly when needed. For example, hello, I need a A, you don't give me B ah.
$container->bind (' A ', function () { return new B (); just); $a = $container->make (' a ');
Summarize
- Dependency injection is an implementation of control inversion, which realizes code decoupling and facilitates unit testing. Because it does not need to know the classes on which it depends, it is only necessary to know that the class on which it is dependent implements the method it needs. You need me, you don't know me/(ㄒoㄒ)/~~
- Control inversion provides a regulatory system that enables automatic injection of dependency resolution, and typically provides a reference to a dependent object instance by a container.