Laravel实现构造函数自动依赖注入的方法


Posted in PHP onMarch 16, 2016

本文实例讲述了Laravel实现构造函数自动依赖注入的方法。分享给大家供大家参考,具体如下:

在Laravel的构造函数中可以实现自动依赖注入,而不需要实例化之前先实例化需要的类,如代码所示:

<?php
namespace Lio\Http\Controllers\Forum;
use Lio\Forum\Replies\ReplyRepository;
use Lio\Forum\Threads\ThreadCreator;
use Lio\Forum\Threads\ThreadCreatorListener;
use Lio\Forum\Threads\ThreadDeleterListener;
use Lio\Forum\Threads\ThreadForm;
use Lio\Forum\Threads\ThreadRepository;
use Lio\Forum\Threads\ThreadUpdaterListener;
use Lio\Http\Controllers\Controller;
use Lio\Tags\TagRepository;
class ForumThreadsController extends Controller implements ThreadCreatorListener, ThreadUpdaterListener, ThreadDeleterListener
{
 protected $threads;
 protected $tags;
 protected $currentSection;
 protected $threadCreator;
 public function __construct(
  ThreadRepository $threads,
  ReplyRepository $replies,
  TagRepository $tags,
  ThreadCreator $threadCreator
 ) {
  $this->threads = $threads;
  $this->tags = $tags;
  $this->threadCreator = $threadCreator;
  $this->replies = $replies;
 }
}

注意构造函数中的几个类型约束,其实并没有地方实例化这个Controller并把这几个类型的参数传进去,Laravel会自动检测类的构造函数中的类型约束参数,并自动识别是否初始化并传入。

源码vendor/illuminate/container/Container.php中的build方法:

$constructor = $reflector->getConstructor();
dump($constructor);

这里会解析类的构造函数,在这里打印看:

Laravel实现构造函数自动依赖注入的方法

它会找出构造函数的参数,再看完整的build方法进行的操作:

public function build($concrete, array $parameters = [])
{
 // If the concrete type is actually a Closure, we will just execute it and
 // hand back the results of the functions, which allows functions to be
 // used as resolvers for more fine-tuned resolution of these objects.
 if ($concrete instanceof Closure) {
  return $concrete($this, $parameters);
 }
 $reflector = new ReflectionClass($concrete);
 // If the type is not instantiable, the developer is attempting to resolve
 // an abstract type such as an Interface of Abstract Class and there is
 // no binding registered for the abstractions so we need to bail out.
 if (! $reflector->isInstantiable()) {
  $message = "Target [$concrete] is not instantiable.";
  throw new BindingResolutionContractException($message);
 }
 $this->buildStack[] = $concrete;
 $constructor = $reflector->getConstructor();
 // If there are no constructors, that means there are no dependencies then
 // we can just resolve the instances of the objects right away, without
 // resolving any other types or dependencies out of these containers.
 if (is_null($constructor)) {
  array_pop($this->buildStack);
  return new $concrete;
 }
 $dependencies = $constructor->getParameters();
 // Once we have all the constructor's parameters we can create each of the
 // dependency instances and then use the reflection instances to make a
 // new instance of this class, injecting the created dependencies in.
 $parameters = $this->keyParametersByArgument(
  $dependencies, $parameters
 );
 $instances = $this->getDependencies(
  $dependencies, $parameters
 );
 array_pop($this->buildStack);
 return $reflector->newInstanceArgs($instances);
}

具体从容器中获取实例的方法:

protected function resolveClass(ReflectionParameter $parameter)
{
 try {
  return $this->make($parameter->getClass()->name);
 }
 // If we can not resolve the class instance, we will check to see if the value
 // is optional, and if it is we will return the optional parameter value as
 // the value of the dependency, similarly to how we do this with scalars.
 catch (BindingResolutionContractException $e) {
  if ($parameter->isOptional()) {
   return $parameter->getDefaultValue();
  }
  throw $e;
 }
}

框架底层通过Reflection反射为开发节省了很多细节,实现了自动依赖注入。这里不做继续深入研究了。

写了一个模拟这个过程的类测试:

<?php
class kulou
{
 //
}
class junjun
{
 //
}
class tanteng
{
 private $kulou;
 private $junjun;
 public function __construct(kulou $kulou,junjun $junjun)
 {
  $this->kulou = $kulou;
  $this->junjun = $junjun;
 }
}
//$tanteng = new tanteng(new kulou(),new junjun());
$reflector = new ReflectionClass('tanteng');
$constructor = $reflector->getConstructor();
$dependencies = $constructor->getParameters();
print_r($dependencies);exit;

原理是通过ReflectionClass类解析类的构造函数,并且取出构造函数的参数,从而判断依赖关系,从容器中取,并自动注入。

转自:小谈博客 http://www.tantengvip.com/2016/01/laravel-construct-ioc/

希望本文所述对大家基于Laravel框架的PHP程序设计有所帮助。

PHP 相关文章推荐
Classes and Objects in PHP5-面向对象编程 [1]
Oct 09 PHP
PHP DataGrid 实现代码
Aug 12 PHP
PHP中的MYSQL常用函数(php下操作数据库必备)
Sep 12 PHP
如何解决CI框架的Disallowed Key Characters错误提示
Jul 05 PHP
使用GDB调试PHP代码,解决PHP代码死循环问题
Mar 02 PHP
php操作redis缓存方法分享
Jun 03 PHP
php生成图片验证码
Jun 09 PHP
PHP变量赋值、代入给JavaScript中的变量
Jun 29 PHP
thinkPHP实现多字段模糊匹配查询的方法
Dec 01 PHP
PHP基于关联数组20行代码搞定约瑟夫问题示例
Nov 07 PHP
PHP实现的解汉诺塔问题算法示例
Aug 06 PHP
PHP日志LOG类定义与用法示例
Sep 06 PHP
PHP 二维数组和三维数组的过滤
Mar 16 #PHP
详解php中反射的应用
Mar 15 #PHP
php实现图片上传并进行替换操作
Mar 15 #PHP
php模板引擎技术简单实现
Mar 15 #PHP
9个比较实用的php代码片段
Mar 15 #PHP
Laravel使用Caching缓存数据减轻数据库查询压力的方法
Mar 15 #PHP
php图片添加文字水印实现代码
Mar 15 #PHP
You might like
基于php上传图片重命名的6种解决方法的详细介绍
2013/04/28 PHP
使用PHP遍历文件目录与清除目录中文件的实现详解
2013/06/24 PHP
destoon找回管理员密码的方法
2014/06/21 PHP
php插入排序法实现数组排序实例
2015/02/16 PHP
使用PHP如何实现高效安全的ftp服务器(二)
2015/12/30 PHP
PHP实现上传多文件示例代码
2017/02/20 PHP
Jquery进度条插件 Progress Bar小问题解决
2011/07/12 Javascript
浅析JS刷新框架中的其他页面 &amp;&amp; JS刷新窗口方法汇总
2013/07/08 Javascript
document.write()及其输出内容的样式、位置控制
2013/08/12 Javascript
JavaScript实现的购物车效果可以运用在好多地方
2014/05/09 Javascript
深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解
2015/03/05 Javascript
jquery UI Datepicker时间控件的使用方法(终结版)
2015/11/07 Javascript
JS使用onerror捕获异常示例
2016/08/03 Javascript
jQuery获取file控件中图片的宽高与大小
2016/08/04 Javascript
nodejs中向HTTP响应传送进程的输出
2017/03/19 NodeJs
用ES6写全屏滚动插件的示例代码
2018/05/02 Javascript
Vue项目webpack打包部署到Tomcat刷新报404错误问题的解决方案
2018/05/15 Javascript
JS删除String里某个字符的方法
2021/01/06 Javascript
vue实现的封装全局filter并统一管理操作示例
2020/02/02 Javascript
JS实现盒子拖拽效果
2020/02/06 Javascript
如何使用JS console.log()技巧提高工作效率
2020/10/14 Javascript
python重试装饰器示例
2014/02/11 Python
Python __setattr__、 __getattr__、 __delattr__、__call__用法示例
2015/03/06 Python
Python入门_浅谈for循环、while循环
2017/05/16 Python
python实现求特征选择的信息增益
2018/12/18 Python
python文件写入write()的操作
2019/05/14 Python
scrapy-redis源码分析之发送POST请求详解
2019/05/15 Python
哪些是python中web开发框架
2020/06/17 Python
如何向scrapy中的spider传递参数的几种方法
2020/11/18 Python
苏格兰在线威士忌商店:The Whisky Barrel
2019/05/07 全球购物
企划主管岗位职责
2013/12/12 职场文书
公司市场专员岗位职责
2014/06/29 职场文书
司法局群众路线教育实践活动整改措施
2014/09/17 职场文书
幼儿园个人师德总结
2015/02/06 职场文书
2015年挂职干部工作总结
2015/05/14 职场文书
GTX1650super好不好 gtx1650super显卡属于什么级别
2022/04/08 数码科技