The Laravel container contains inversion of control and dependency injection. To use it, bind the object and use make to fetch it if necessary.
Our usual call is as follows
$config = $container->make('config');
$connection = new Connection($this->config);Copy the code
The benefit of this is that you don’t have to create an instance directly, the method passes the same value, and the instance can be shared across multiple locations.
But what does this have to do with dependency injection? In real dependency injection, you don’t need to pass any parameter values to the method, just specify the method parameter types, and the code automatically looks up the relational dependency auto-injection.
This feature can be reflected in Laravel Controller, Job, etc., as follows:
class TestController extends Controller
{
public function anyConsole(Request $request, Auth $input)
{
//todo
}
}Copy the code
Let’s take a look at how he implements automatic dependency injection:
Index.php calls the Kernel through the multi-layer Kernel pipeline, and then to the Router through the multi-layer middleware pipeline. Final positioning to Illuminate/Routing/Route. The PHP on line 124.
public function run(Request $request)
{
$this->container = $this->container ? : new Container; try {if (! is_string($this->action['uses']) {return $this->runCallable($request);
}
if ($this->customDispatcherIsBound()) {
return $this->runWithCustomDispatcher($request);
}
return $this->runController($request);
} catch (HttpResponseException $e) {
return $e->getResponse(); }} to judge$this->action['uses'] (format: \App\Http\Controller\Datacenter\RealTimeController@anyConsole)$this->customDispatcherIsBound Checks whether a user-defined route is bound. Then jump to$this->runController($request)。
protected function runController(Request $request)
{
list($class.$method) = explode(The '@'.$this->action['uses']);
$parameters = $this->resolveClassMethodDependencies(
$this->parametersWithoutNulls(), $class.$method
);
if (! method_exists($instance = $this->container->make($class), $method)) {
throw new NotFoundHttpException;
}
return call_user_func_array([$instance.$method].$parameters);
}
$this- > resolveClassMethodDependencies a look at the name will know that this method is the way we are looking for.$this->parametersWithoutNulls() is a filter for null characters,$class,$methodThe lines are as follows: App, Http, Controller, Datacenter, RealTimeController and anyConsole. protectedfunction resolveClassMethodDependencies(array $parameters.$instance.$method)
{
if (! method_exists($instance.$method)) {
return $parameters;
}
return $this->resolveMethodDependencies(
$parameters, new ReflectionMethod($instance.$method)); } new ReflectionMethod($instance.$method) is the reflection object that gets the class method. See documentation: http://www.php.net/manual/zh/class.reflectionmethod.php below to jump to Illuminate/Routing/RouteDependencyResolverTrait. PHP line 54. publicfunction resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector)
{
$originalParameters = $parameters;
foreach ($reflector->getParameters() as $key= >$parameter) {
$instance = $this->transformDependency(
$parameter.$parameters.$originalParameters
);
if (! is_null($instance)) {
$this->spliceIntoParameters($parameters.$key.$instance); }}return $parameters; } get the class parameter array by reflecting the class method and pass it through to$this- > transformDependency method. Called if the instance cannot be obtained$this->spliceIntoParameters knows this parameter. protectedfunction transformDependency(ReflectionParameter $parameter.$parameters.$originalParameters)
{
$class = $parameter->getClass();
if ($class&&!$this->alreadyInParameters($class->name, $parameters)) {
return $this->container->make($class->name); }}Copy the code
Finally, I see the shadow of the container, and yes, the object is retrieved by the make method of the container. At this point, the parameters are constructed and will eventually be called back by call_user_func_array of the runController method.
Conclusion:
1. The principle of dependency injection is to use class method reflection to get parameter types, and then use containers to construct instances. Then use the callback function to call up. 2. The injected object constructor cannot have arguments. Otherwise, an error will be reported. Dependency injection is good, but it must be invoked by the Router class, otherwise it cannot be injected using new. This is why only Controller and Job classes can use this feature.