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 相关文章推荐
php cli 方式 在crotab中运行解决
Feb 08 PHP
PHP里的中文变量说明
Jul 23 PHP
AJAX的跨域访问-两种有效的解决方法介绍
Jun 22 PHP
destoon二次开发入门示例
Jun 20 PHP
php通过asort()给关联数组按照值排序的方法
Mar 18 PHP
变量在 PHP7 内部的实现(一)
Dec 21 PHP
使用php实现从身份证中提取生日
May 09 PHP
Zend Framework实现自定义过滤器的方法
Dec 09 PHP
php微信公众号开发(2)百度BAE搭建和数据库使用
Dec 15 PHP
PHP字符串逆序排列实现方法小结【strrev函数,二分法,循环法,递归法】
Jan 13 PHP
yii2 commands模式以及配置crontab定时任务的方法
Aug 19 PHP
php字符串过滤strip_tags()函数用法实例分析
Jun 24 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实现zip压缩文件解压缩代码分享(简单易懂)
2014/05/10 PHP
PHP使用适合阅读的格式显示文件大小的方法
2015/03/05 PHP
Thinkphp无限级分类代码
2015/11/11 PHP
Laravel框架基于ajax和layer.js实现无刷新删除功能示例
2019/01/17 PHP
设定php简写功能的方法
2019/11/28 PHP
TBCompressor js代码压缩
2011/01/05 Javascript
js图片自动轮播代码分享(js图片轮播)
2014/05/06 Javascript
jquery操作HTML5 的data-*的用法实例分享
2014/08/17 Javascript
JS应用正则表达式转换大小写示例
2014/09/18 Javascript
javascript引用赋值(地址传值)用法实例
2015/01/13 Javascript
Node.js和MongoDB实现简单日志分析系统
2015/04/25 Javascript
基于JS实现省市联动效果代码分享
2016/06/06 Javascript
js中用cssText设置css样式的简单方法
2016/09/19 Javascript
前端开发之CSS原理详解
2017/03/11 Javascript
详解angular element()方法使用
2017/04/08 Javascript
Vue应用部署到服务器的正确方式
2017/07/15 Javascript
微信小程序之页面跳转和参数传递的实现
2017/09/29 Javascript
js 只比较时间大小的实例
2017/10/26 Javascript
使用vue-router完成简单导航功能【推荐】
2018/06/28 Javascript
微信实现自动跳转到用其他浏览器打开指定APP下载
2019/02/15 Javascript
详解element-ui动态限定的日期范围选择器代码片段
2020/07/03 Javascript
一篇文章让你搞懂JavaScript 原型和原型链
2020/11/23 Javascript
用Python实现服务器中只重载被修改的进程的方法
2015/04/30 Python
python ddt实现数据驱动
2018/03/14 Python
详解Python3序列赋值、序列解包
2019/05/14 Python
利用Python实现Shp格式向GeoJSON的转换方法
2019/07/09 Python
利用4行Python代码监测每一行程序的运行时间和空间消耗
2020/04/22 Python
从python读取sql的实例方法
2020/07/21 Python
Visual Studio Code搭建django项目的方法步骤
2020/09/17 Python
python Gabor滤波器讲解
2020/10/26 Python
Emporio Armani腕表天猫官方旗舰店:乔治·阿玛尼为年轻人设计的副线品牌
2017/07/02 全球购物
学雷锋活动倡议书
2014/08/30 职场文书
简单的离婚协议书范本
2014/11/16 职场文书
培训后的感想
2015/08/07 职场文书
nginx搭建图片服务器的过程详解(root和alias的区别)
2021/03/31 Servers
Nginx隐藏式跳转(浏览器URL跳转后保持不变)
2022/04/07 Servers