Laravel 依赖注入源码解析

前端之家收集整理的这篇文章主要介绍了Laravel 依赖注入源码解析前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

在 Laravel 的控制器的构造方法或者成员方法,都可以通过类型约束的方式使用依赖注入,如:

  1. public function store(Request $request)
  2. {
  3. //TODO
  4. }

这里 $request 参数就使用了类型约束,Request 是类型约束的类型,它是一个类:IlluminateHttpRequest.

本文研究 Laravel 的依赖注入原理,为什么这样定义不需要实例化就可以直接使用 Request 的方法呢?只是框架帮我们实例化并传参了,我们看看这个过程。

1.路由定义

从源头开始看起,在路由定义文件中定义了这么一个路由:

  1. Route::resource('/role','Admin\RoleController');

这是一个资源型的路由,Laravel 会自动生成增删改查的路由入口。

本文开头的 store 方法就是一个控制器的方法,图中可见路由定义的 Action 也是:AppHttpControllersAdminRoleController@store

路由方法解析

根据路由定义找到控制器和方法,这个过程在 dispatch 方法中实现。

文件:vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.PHP

  1. public function dispatch(Route $route,$controller,$method)
  2. {
  3. $parameters = $this->resolveClassMethodDependencies(
  4. $route->parametersWithoutNulls(),$method
  5. );
  6. if (method_exists($controller,'callAction')) {
  7. return $controller->callAction($method,$parameters);
  8. }
  9. return $controller->{$method}(...array_values($parameters));
  10. }

这里 resolveClassMethodDependencies 方法,“顾名思义”这个方法的作用是从类的方法获取依赖对象:

  1. protected function resolveClassMethodDependencies(array $parameters,$instance,$method)
  2. {
  3. if (! method_exists($instance,$method)) {
  4. return $parameters;
  5. }
  6. return $this->resolveMethodDependencies(
  7. $parameters,new ReflectionMethod($instance,$method)
  8. );
  9. }

这里重点就是用到了 PHP 的反射,注意 RelectionMethod 方法,它获取到类的方法参数列表,可以知道参数的类型约束,参数名称等等。

这里的 $instance 参数就是 RoleController 控制器类,$method 参数就是方法名称 strore.

2.获取依赖对象的示例

方法的参数中获取了依赖对象的约束类型,就可以实例化这个依赖的对象。

  1. protected function transformDependency(ReflectionParameter $parameter,$parameters)
  2. {
  3. $class = $parameter->getClass();
  4. // If the parameter has a type-hinted class,we will check to see if it is already in
  5. // the list of parameters. If it is we will just skip it as it is probably a model
  6. // binding and we do not want to mess with those; otherwise,we resolve it here.
  7. if ($class && ! $this->alreadyInParameters($class->name,$parameters)) {
  8. return $parameter->isDefaultValueAvailable()
  9. ? $parameter->getDefaultValue()
  10. : $this->container->make($class->name);
  11. }
  12. }

根据类名从容器中获取对象,这个绑定对象实例的过程在服务提供者中先定义和了。

然后把实例化的对象传入到 store 方法中,就可以使用依赖的对象了。

3.关于 PHP 反射

举个使用 ReflectionMethod 的例子。

  1. class Demo
  2. {
  3. private $request;
  4. public function store(Request $request)
  5. {
  6. }
  7. }

打印出 new ReflectionMethod(Demo::class,‘store’) 的内容如图:

可以得出这个方法的参数列表,参数的约束类型,如 typeHint,IlluminateHttpRequest.

根据类名可以从容器中获取一开始通过服务提供者绑定的实例。

(原文地址:https://blog.tanteng.me/2018/...

猜你在找的设计模式相关文章