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 配置open_basedir 让各虚拟站点独立运行
Nov 12 PHP
PHP UTF8中文字符截断函数代码
Sep 11 PHP
PHP开发框架Laravel数据库操作方法总结
Sep 03 PHP
php计算两个日期相差天数的方法
Mar 14 PHP
php基础设计模式大全(注册树模式、工厂模式、单列模式)
Aug 31 PHP
PHP远程调试之XDEBUG
Dec 29 PHP
PHP访问数据库集群的方法小结
Mar 14 PHP
PHP获取客户端及服务器端IP的封装类
Jul 21 PHP
Yii2简单实现多语言配置的方法
Jul 23 PHP
在thinkphp5.0路径中实现去除index.php的方式
Oct 16 PHP
TP5多入口设置实例讲解
Dec 15 PHP
php的对象传值与引用传值代码实例讲解
Feb 26 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 similar_text 字符串的相似性比较函数
2010/05/26 PHP
php异常处理方法实例汇总
2015/06/24 PHP
网页的分页下标生成代码(PHP后端方法)
2016/02/03 PHP
PHP微信开发用Cache 解决数据缓存
2016/07/11 PHP
Windows上php5.6操作mongodb数据库示例【配置、连接、获取实例】
2019/02/13 PHP
js change,propertychange,input事件小议
2011/12/20 Javascript
JavaScript中将一个值转换为字符串的方法分析[译]
2012/09/21 Javascript
理解Javascript闭包
2013/11/01 Javascript
javascript alert乱码的解决方法
2013/11/05 Javascript
JavaScript中的函数重载深入理解
2014/08/04 Javascript
js添加select下默认的option的value和text的方法
2014/10/19 Javascript
node.js中的fs.stat方法使用说明
2014/12/16 Javascript
jquery实现未经美化的简洁TAB菜单效果
2015/08/28 Javascript
JavaScript使用DeviceOne开发实战(一) 配置和起步
2015/12/01 Javascript
基于jQuery的AJAX和JSON实现纯html数据模板
2016/08/09 Javascript
JavaScript使用原型和原型链实现对象继承的方法详解
2017/04/05 Javascript
详解Vue源码之数据的代理访问
2018/12/11 Javascript
jQuery选择器之基本选择器用法实例分析
2019/02/19 jQuery
详解react组件通讯方式(多种)
2020/05/06 Javascript
纯js+css实现在线时钟
2020/08/18 Javascript
[57:41]Secret vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python内建函数之raw_input()与input()代码解析
2017/10/26 Python
python跳过第一行快速读取文件内容的实例
2018/07/12 Python
python采集微信公众号文章
2018/12/20 Python
Python中使用遍历在列表中添加字典遇到的坑
2019/02/27 Python
python操作文件的参数整理
2019/06/11 Python
python超时重新请求解决方案
2019/10/21 Python
基于python模拟TCP3次握手连接及发送数据
2020/11/06 Python
Python读取图像并显示灰度图的实现
2020/12/01 Python
西班牙电子产品购物网站:Electronicamente
2018/07/26 全球购物
司机岗位职责
2013/11/15 职场文书
服装厂厂长职责
2013/12/16 职场文书
小学岗位竞聘方案
2014/01/22 职场文书
法学求职信
2014/06/22 职场文书
Django框架之路由用法
2022/06/10 Python
win10输入法不见了只能打出字母怎么解决?
2022/08/05 数码科技