通过源码解析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 相关文章推荐
substr()函数中文版
Oct 09 PHP
比较全面的PHP数组的使用方法小结
Sep 23 PHP
Codeigniter整合Tank Auth权限类库详解
Jun 12 PHP
CodeIgniter中使用cookie的三种方式详解
Jul 18 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
Sep 02 PHP
php实现根据url自动生成缩略图的方法
Sep 23 PHP
php+mysqli批量查询多张表数据的方法
Jan 29 PHP
php实现在服务器上创建目录的方法
Mar 16 PHP
PHP实现连接设备、通讯和发送命令的方法
Oct 13 PHP
超详细的php用户注册页面填写信息完整实例(附源码)
Nov 17 PHP
WordPress中用于更新伪静态规则的PHP代码实例讲解
Dec 18 PHP
浅析php如何实现爬取数据原理
Sep 27 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
环境会对咖啡种植有什么影响
2021/03/03 咖啡文化
memcache命令启动参数中文解释
2014/01/13 PHP
php实现的一段简单概率相关代码
2016/05/30 PHP
php生成与读取excel文件
2016/10/14 PHP
php快速导入大量数据的实例方法
2019/09/23 PHP
laravel5.5添加echarts实现画图功能的方法
2019/10/09 PHP
客户端脚本中常常出现的一些问题和调试技巧
2007/01/09 Javascript
Array栈方法和队列方法的特点说明
2014/01/24 Javascript
js显示文本框提示文字的方法
2015/05/07 Javascript
javascript:void(0)是什么意思及href=#与href=javascriptvoid(0)的区别
2015/11/13 Javascript
js自调用匿名函数的三种写法(推荐)
2016/08/19 Javascript
使用jsonp实现跨域获取数据实例讲解
2016/12/25 Javascript
Vue.js中兄弟组件之间互相传值实例
2017/06/01 Javascript
Canvas实现微信红包照片效果
2018/08/21 Javascript
解决vue单页路由跳转后scrollTop的问题
2018/09/03 Javascript
在vue项目中引用Iview的方法
2018/09/14 Javascript
node.js使用redis储存session的方法
2018/09/26 Javascript
在移动端使用vue-router和keep-alive的方法示例
2018/12/02 Javascript
JavaScript学习笔记之DOM操作实例分析
2019/01/08 Javascript
用npm-run实现自动化任务的方法示例
2019/01/14 Javascript
js实现坦克移动小游戏
2019/10/28 Javascript
python读取csv文件示例(python操作csv)
2014/03/11 Python
Python def函数的定义、使用及参数传递实现代码
2014/08/10 Python
Python中变量交换的例子
2014/08/25 Python
python 简单搭建阻塞式单进程,多进程,多线程服务的实例
2017/11/01 Python
python2.7使用plotly绘制本地散点图和折线图
2019/04/02 Python
详解用Python为直方图绘制拟合曲线的两种方法
2019/08/21 Python
wxPython实现绘图小例子
2019/11/19 Python
Python3如何在服务器打印资产信息
2020/08/27 Python
Python监听键盘和鼠标事件的示例代码
2020/11/18 Python
Lookfantastic瑞典:英国知名美妆购物网站
2018/04/06 全球购物
澳大利亚在线批发商:Simply Wholesale
2021/02/24 全球购物
二手房买卖协议书
2014/04/10 职场文书
淘宝好评语大全
2014/05/05 职场文书
工作简报格式范文
2015/07/21 职场文书
Node与Python 双向通信的实现代码
2021/07/16 Javascript