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实现小型站点广告管理
Oct 09 PHP
我的论坛源代码(三)
Oct 09 PHP
PHP HTML代码串 截取实现代码
Jun 29 PHP
php 网页游戏开发入门教程一(webgame+design)
Oct 26 PHP
php下将多个数组合并成一个数组的方法与实例代码
Feb 03 PHP
php中magic_quotes_gpc对unserialize的影响分析
Dec 16 PHP
PHP stream_context_create()函数的使用示例
May 12 PHP
php实现json编码的方法
Jul 30 PHP
PHP实现长文章分页实例代码(附源码)
Feb 03 PHP
深入浅析yii2-gii自定义模板的方法
Apr 26 PHP
PHP数据库操作Helper类完整实例
May 11 PHP
详细对比php中类继承和接口继承
Oct 11 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
ThinkPHP Mobile使用方法简明教程
2014/06/18 PHP
windows下apache搭建php开发环境
2015/08/27 PHP
javascript基本语法分析说明
2008/06/15 Javascript
js前台判断开始时间是否小于结束时间
2012/02/23 Javascript
JS清除IE浏览器缓存的方法
2013/07/26 Javascript
JavaScript中number转换成string介绍
2014/12/31 Javascript
JS对字符串编码的几种方式使用指南
2015/05/14 Javascript
jquery实现未经美化的简洁TAB菜单效果
2015/08/28 Javascript
实现高性能JavaScript之执行与加载
2016/01/30 Javascript
一波JavaScript日期判断脚本分享
2016/03/06 Javascript
jQuery获取父元素节点、子元素节点及兄弟元素节点的方法
2016/04/14 Javascript
超实用的javascript时间处理总结
2016/08/16 Javascript
利用JavaScript实现拖拽改变元素大小
2016/12/14 Javascript
利用JQUERY实现多个AJAX请求等待的实例
2017/12/14 jQuery
element 结合vue 在表单验证时有值却提示错误的解决办法
2018/01/22 Javascript
浅谈微信页面入口文件被缓存解决方案
2018/09/29 Javascript
JS 正则表达式验证密码、邮箱格式的实例代码
2018/10/28 Javascript
Vue实现微信支付功能遇到的坑
2019/06/05 Javascript
vue路由权限校验功能的实现代码
2020/06/07 Javascript
浅谈JavaScript 声明提升
2020/09/14 Javascript
python通过openpyxl生成Excel文件的方法
2015/05/12 Python
Python中处理字符串的相关的len()方法的使用简介
2015/05/19 Python
在windows下快速搭建web.py开发框架方法
2016/04/22 Python
Windows 8.1 64bit下搭建 Scrapy 0.22 环境
2018/11/18 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
浅析Python __name__ 是什么
2020/07/07 Python
python利用paramiko实现交换机巡检的示例
2020/09/22 Python
用CSS3和table标签实现一个圆形轨迹的动画的示例代码
2019/01/17 HTML / CSS
HTML5本地存储之IndexedDB
2017/06/16 HTML / CSS
美国领先的家庭智能音响系统品牌:Sonos
2018/07/20 全球购物
什么是数组名
2012/05/10 面试题
关于VPN
2012/06/10 面试题
出国留学自荐信
2013/10/25 职场文书
实验心得体会范文
2016/01/25 职场文书
python基础之模块的导入
2021/10/24 Python
浅谈Redis变慢的原因及排查方法
2022/06/21 Redis