通过源码解析Laravel的依赖注入


Posted in PHP onJanuary 22, 2018

前言

众所周知,php的框架数不胜数,近几年,一个以优雅著称的框架,渐渐被国内phper所知道,并且开始使用,但是larave有一个很明显的缺点就是,他的文档内容少的可怜。

本文将给大家详细介绍关于Laravel依赖注入的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

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

public function store(Request $request)
{
 //TODO
}

这里 $request 参数就使用了类型约束,Request 是一个类:\Illuminate\Http\Request,表示参数必须是这个类或子类。

本文通过分析 Laravel 的源码,看为什么方法中不需要传入实例就可以直接使用 Request 呢?只是框架自动帮我们实例化并传参了。

1.路由定义

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

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

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

通过源码解析Laravel的依赖注入

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

路由方法解析

根据路由定义找到控制器和方法,执行具体的方法在 dispatch 方法中实现。

(文件:vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php)

public function dispatch(Route $route, $controller, $method)
{
 $parameters = $this->resolveClassMethodDependencies(
  $route->parametersWithoutNulls(), $controller, $method
 );
 
 if (method_exists($controller, 'callAction')) {
  return $controller->callAction($method, $parameters);
 }
 
 return $controller->{$method}(...array_values($parameters));
}

首先 resolveClassMethodDependencies 方法,“顾名思义”是根据类的方法参数获取依赖对象,然后再调用类的方法并把对象参数注入。

如果有多个依赖对象,也会 foreach 依次解析出来作为参数注入。

获取依赖对象示例的代码:

protected function resolveClassMethodDependencies(array $parameters, $instance, $method)
{
 if (! method_exists($instance, $method)) {
  return $parameters;
 }
 
 return $this->resolveMethodDependencies(
  $parameters, new ReflectionMethod($instance, $method)
 );
}

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

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

2.获取依赖对象的示例

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

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

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

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

3.关于 PHP 反射

举个使用 ReflectionMethod 的例子。

class Demo
{
 private $request;
 public function store(Request $request)
 {
 }
}

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

通过源码解析Laravel的依赖注入

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

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
浅谈PHP语法(1)
Oct 09 PHP
使用PHP提取视频网站页面中的FLASH地址的代码
Apr 17 PHP
兼容性最强的PHP生成缩略图的函数代码(修改版)
Jan 18 PHP
Windows下利用Gvim写PHP产生中文乱码问题解决方法
Apr 20 PHP
php中如何判断一个网页请求是ajax请求还是普通请求
Aug 10 PHP
ThinkPHP实现动态包含文件的方法
Nov 29 PHP
YII CLinkPager分页类扩展增加显示共多少页
Jan 29 PHP
php获取文件后缀的9种方法
Mar 22 PHP
php字符集转换
Jan 23 PHP
PHP+MySQL实现输入页码跳转到指定页面功能示例
Jun 01 PHP
ThinkPHP like模糊查询,like多匹配查询,between查询,in查询,一般查询书写方法
Sep 26 PHP
phpStorm2020 注册码
Sep 17 PHP
phpstorm 正则匹配删除空行、注释行(替换注释行为空行)
Jan 21 #PHP
php语言注释,单行注释和多行注释
Jan 21 #PHP
PHP注释语法规范与命名规范详解篇
Jan 21 #PHP
php nginx 实时输出的简单实现方法
Jan 21 #PHP
Lumen timezone 时区设置方法(慢了8个小时)
Jan 20 #PHP
PHP Class SoapClient not found解决方法
Jan 20 #PHP
tp5(thinkPHP5)操作mongoDB数据库的方法
Jan 20 #PHP
You might like
mysql alter table命令修改表结构实例详解
2016/09/24 PHP
浅谈php处理后端&接口访问超时的解决方法
2016/10/29 PHP
Yii2框架制作RESTful风格的API快速入门教程
2016/11/08 PHP
PHPMailer发送邮件
2016/12/28 PHP
PHP实现简单的模板引擎功能示例
2017/09/02 PHP
setTimeout和setInterval的区别你真的了解吗?
2011/03/31 Javascript
jQuery EasyUI API 中文文档 - ProgressBar 进度条
2011/09/29 Javascript
jQuery选择器用法实例详解
2015/12/17 Javascript
实例讲解Jquery中隐藏hide、显示show、切换toggle的用法
2016/05/13 Javascript
jQuery Ajax 全局调用封装实例代码详解
2016/06/02 Javascript
JS实现iframe编辑器光标位置插入内容的方法(兼容IE和Firefox)
2016/06/24 Javascript
JavaScript直播评论发弹幕切图功能点集合效果代码
2016/06/26 Javascript
使用jQuery监听扫码枪输入并禁止手动输入的实现方法(推荐)
2017/03/21 jQuery
easyui combogrid实现本地模糊搜索过滤多列
2017/05/13 Javascript
Angular4实现动态添加删除表单输入框功能
2017/08/11 Javascript
vue 项目地址去掉 #的方法
2018/10/20 Javascript
浅谈Vuex的this.$store.commit和在Vue项目中引用公共方法
2020/07/24 Javascript
[15:56]Heroes18_暗影萨满(完美)
2014/10/31 DOTA
[46:48]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第三局
2016/02/25 DOTA
Python和perl实现批量对目录下电子书文件重命名的代码分享
2014/11/21 Python
python读写ini配置文件方法实例分析
2015/06/30 Python
Python 2.x如何设置命令执行的超时时间实例
2017/10/19 Python
python装饰器-限制函数调用次数的方法(10s调用一次)
2018/04/21 Python
flask-socketio实现WebSocket的方法
2018/07/31 Python
24个canvas基础知识小结
2014/12/17 HTML / CSS
使用phonegap查找联系人的实现方法
2017/03/31 HTML / CSS
AmazeUI 加载进度条的实现示例
2020/08/20 HTML / CSS
美国顶级户外凉鞋品牌:Chacos
2017/03/27 全球购物
英国No.1体育用品零售商:SportsDirect.com
2019/10/16 全球购物
小学新学期教师寄语
2014/01/18 职场文书
社区先进事迹材料
2014/05/19 职场文书
小学国旗下的演讲稿
2014/08/28 职场文书
2015年护士长个人工作总结
2015/04/24 职场文书
优秀班主任工作总结2015
2015/05/25 职场文书
2016年情人节广告语
2016/01/28 职场文书
Win2008系统搭建DHCP服务器
2022/06/25 Servers