通过源码解析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作为网站开发语言的原因分享
Jan 03 PHP
phpmail类发送邮件函数代码
Feb 20 PHP
discuz免激活同步登入代码修改方法(discuz同步登录)
Dec 24 PHP
php加速器eAccelerator的配置参数、API详解
May 05 PHP
yii操作cookie实例简介
Jul 09 PHP
php通过session防url攻击方法
Dec 10 PHP
PHP中使用php5-ffmpeg撷取视频图片实例
Jan 07 PHP
php添加数据到xml文件的简单例子
Sep 08 PHP
php抛出异常与捕捉特定类型的异常详解
Oct 26 PHP
PHP实现ASCII码与字符串相互转换的方法
Apr 29 PHP
Thinkphp5.0框架的Db操作实例分析【连接、增删改查、链式操作等】
Oct 11 PHP
yii2.0框架实现上传excel文件后导入到数据库的方法示例
Apr 13 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
snoopy 强大的PHP采集类使用实例代码
2010/12/09 PHP
PHP实现的限制IP投票程序IP来源分析
2016/05/04 PHP
解决微信授权回调页面域名只能设置一个的问题
2016/12/11 PHP
PHP设计模式(一)工厂模式Factory实例详解【创建型】
2020/05/02 PHP
由Javascript实现的页面日历
2011/11/04 Javascript
JS操作图片(增,删,改) 例子
2013/04/17 Javascript
CSS鼠标响应事件经过、移动、点击示例介绍
2013/09/04 Javascript
JavaScript设计模式之工厂方法模式介绍
2014/12/28 Javascript
js实现从右向左缓缓浮出网页浮动层广告的方法
2015/05/09 Javascript
Node.js事件驱动
2015/06/18 Javascript
基于jQuery实现选取月份插件附源码下载
2015/12/28 Javascript
jquery validation验证表单插件
2017/01/07 Javascript
jQuery中的on与bind绑定事件区别实例详解
2017/02/28 Javascript
微信小程序 监听手势滑动切换页面实例详解
2017/06/15 Javascript
JS+CSS实现网页加载中的动画效果
2017/10/27 Javascript
看看“疫苗查询”小程序有温度的代码
2018/07/31 Javascript
解决vue axios的封装 请求状态的错误提示问题
2018/09/25 Javascript
微信小程序云开发实现云数据库读写权限
2019/05/17 Javascript
关于layui的动态图标不显示的解决方法
2019/09/04 Javascript
js实现整体缩放页面适配移动端
2020/03/31 Javascript
[02:17]2016完美“圣”典风云人物:Sccc专访
2016/12/03 DOTA
[43:03]完美世界DOTA2联赛PWL S2 PXG vs Magma 第二场 11.21
2020/11/24 DOTA
Python socket.error: [Errno 98] Address already in use的原因和解决方法
2014/08/25 Python
Python中os.path用法分析
2015/01/15 Python
在Python程序中操作MySQL的基本方法
2015/07/29 Python
matplotlib简介,安装和简单实例代码
2017/12/26 Python
python 定义n个变量方法 (变量声明自动化)
2018/11/10 Python
简单了解python单例模式的几种写法
2019/07/01 Python
python selenium登录豆瓣网过程解析
2019/08/10 Python
Omio意大利:全欧洲低价大巴、火车和航班搜索和比价
2017/12/02 全球购物
介绍一下Linux内核的排队自旋锁
2014/01/04 面试题
城市规划毕业生求职信
2013/10/10 职场文书
大龄毕业生求职别忘职业规划
2014/03/11 职场文书
迎新晚会策划方案
2014/06/13 职场文书
原料仓仓管员岗位职责
2014/07/08 职场文书
Nginx虚拟主机的搭建的实现步骤
2022/01/18 Servers