php+laravel依赖注入知识点总结


Posted in PHP onNovember 04, 2019

laravel容器包含控制反转和依赖注入,使用起来就是,先把对象bind好,需要时可以直接使用make来取就好。

通常我们的调用如下。

$config = $container->make('config');
$connection = new Connection($this->config);

比较好理解,这样的好处就是不用直接 new 一个实例了,方法传值没啥改变,还可以多处共享此实例。

但这跟依赖注入有什么关系,真正的依赖注入是不需给方法传递任何参数值,只需要指明方法参数类型,代码自动查找关系依赖自动注入。

这个特性在 laravel 的 Controller、Job 等处可以体现,如下:

class TestController extends Controller
{
public function anyConsole(Request $request, Auth $input)
{
//todo
}
}

我们来看下他是怎么实现自动依赖注入的:

由 index.php 调用 Kernel ,经过多层 Kernel 管道调用,再到 Router ,经过多层中间件管道调用。最终定位到

Illuminate/Routing/Route.php 第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();
}
}

判断 $this->action['uses'](格式行如:\App\Http\Controller\Datacenter\RealTimeController@anyConsole)是否字符串, $this->customDispatcherIsBound判断是否绑定了用户自定义路由。然后跳转到 $this->runController($request)。

protected function runController(Request $request)
{
list($class, $method) = explode('@', $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 这个方法一看名字就知道是我们要找的方法。$this->parametersWithoutNulls()是过滤空字符,$class、$method分别行如:\App\Http\Controller\Datacenter\RealTimeController 与 anyConsole。

protected function resolveClassMethodDependencies(array $parameters, $instance, $method)
{
if (! method_exists($instance, $method)) {
return $parameters;
}

return $this->resolveMethodDependencies(
$parameters, new ReflectionMethod($instance, $method)
);
}

new ReflectionMethod($instance, $method) 是拿到类方法的反射对象,参见文档:http://www.php.net/manual/zh/class.reflectionmethod.php

下面跳转到Illuminate/Routing/RouteDependencyResolverTrait.php 第54行。

public function 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;
}

通过反射类方法得到类参数数组,然后遍历传递给 $this->transformDependency 方法。如果实例获取不到则调用 $this->spliceIntoParameters 清楚该参数。

protected function transformDependency(ReflectionParameter $parameter, $parameters, $originalParameters)
{
$class = $parameter->getClass();
if ($class && ! $this->alreadyInParameters($class->name, $parameters)) {
return $this->container->make($class->name);
}
}

终于看到了容器的影子,没错最终对象还是通过容器的 make 方法取出来的。至此参数就构造好了,然后最终会被 runController 方法的 call_user_func_array 回调。

总结:

1. 依赖注入原理其实就是利用类方法反射,取得参数类型,然后利用容器构造好实例。然后再使用回调函数调起。

2. 注入对象构造函数不能有参数。否则会报错。Missing argument 1

3. 依赖注入故然好,但它必须要由 Router 类调起,否则直接用 new方式是无法实现注入的。所以这就为什么只有 Controller 、Job 类才能用这个特性了。

以上就是关于php+laravel依赖注入的全部知识点内容,感谢大家的学习和对三水点靠木的支持。

PHP 相关文章推荐
用PHP生成静态HTML速度快类库
Mar 18 PHP
PHP学习之数组的定义和填充
Apr 17 PHP
获取php页面执行时间,数据库读写次数,函数调用次数等(THINKphp)
Jun 03 PHP
php读取二进制流(C语言结构体struct数据文件)的深入解析
Jun 13 PHP
PHP程序员常见的40个陋习,你中了几个?
Nov 20 PHP
Yii学习总结之安装配置
Feb 22 PHP
详解Window7 下开发php扩展
Dec 31 PHP
Yii清理缓存的方法
Jan 06 PHP
PHP常用设计模式之委托设计模式
Feb 13 PHP
PHP文件上传类实例详解
Apr 08 PHP
PHP实现二维数组根据key进行排序的方法
Dec 30 PHP
php如何获取Http请求
Apr 30 PHP
PHP保存Base64图片base64_decode的问题整理
Nov 04 #PHP
详解laravel passport OAuth2.0的4种模式
Nov 04 #PHP
laravel返回统一格式错误码问题
Nov 04 #PHP
php 中self,this的区别和操作方法实例分析
Nov 04 #PHP
PHP 文件写入和读取操作实例详解【必看篇】
Nov 04 #PHP
PHP连接MySQL数据库的三种方式实例分析【mysql、mysqli、pdo】
Nov 04 #PHP
php ZipArchive实现多文件打包下载实例
Oct 31 #PHP
You might like
PHP动态创建Web站点的方法
2011/08/14 PHP
php批量上传的实现代码
2013/06/09 PHP
PHP编程实现脚本异步执行的方法
2017/08/09 PHP
JQuery 学习笔记 element属性控制
2009/07/23 Javascript
JavaScript自定义DateDiff函数(兼容所有浏览器)
2012/03/01 Javascript
解决jquery submit()提交表单提示:f[s] is not a function
2013/01/23 Javascript
JQuery 图片滚动轮播示例代码
2014/03/24 Javascript
JavaScript也谈内存优化
2014/06/06 Javascript
Jquery+ajax+JAVA(servlet)实现下拉菜单异步取值
2016/03/23 Javascript
浅析JS动态创建元素【两种方法】
2016/04/20 Javascript
Angularjs 实现分页功能及示例代码
2016/09/14 Javascript
javascript轮播图算法
2016/10/21 Javascript
AngularJS select设置默认值的实现方法
2017/08/25 Javascript
新手vue构建单页面应用实例代码
2017/09/18 Javascript
JS实现点击链接切换显示隐藏内容的方法
2017/10/19 Javascript
详解使用React进行组件库开发
2018/02/06 Javascript
Vue中使用create-keyframe-animation与动画钩子完成复杂动画
2019/04/09 Javascript
vue实现移动端轻量日期组件不依赖第三方库的方法
2019/04/28 Javascript
微信小程序如何刷新当前界面的实现方法
2019/06/07 Javascript
微信小程序设置滚动条过程详解
2019/07/25 Javascript
使用apifm-wxapi模块中的问题及解决方法
2019/08/05 Javascript
[48:00]EG vs LGD 2018国际邀请赛淘汰赛BO3 第二场 8.26
2018/08/29 DOTA
[46:23]OG vs EG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python 使用os.remove删除文件夹时报错的解决方法
2017/01/13 Python
Python基础教程之利用期物处理并发
2018/03/29 Python
python opencv实现切变换 不裁减图片
2018/07/26 Python
python mqtt 客户端的实现代码实例
2019/09/25 Python
pytorch实现特殊的Module--Sqeuential三种写法
2020/01/15 Python
Python : turtle色彩控制实例详解
2020/01/19 Python
PyCharm+Pipenv虚拟环境开发和依赖管理的教程详解
2020/04/16 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
python opencv实现图像配准与比较
2021/02/09 Python
会议营销主持词
2015/07/03 职场文书
golang中切片copy复制和等号复制的区别介绍
2021/04/27 Golang
详解Django的MVT设计模式
2021/04/29 Python
Golang Elasticsearches 批量修改查询及发送MQ
2022/04/19 Golang