依赖注入底层反射原理_PHP反射机制实现自动依赖注入

依赖注入又叫控制反转,使用过框架的人应该都不陌生。很多人一看名字就觉得是非常高大上的东西,就对它望而却步,今天解开他它的神秘面纱。废话不多说,直接上代码;

/**

*

* 工具类,使用该类来实现自动依赖注入。

*

*/

class Ioc {

// 获得类的对象实例

public static function getInstance($className) {

$paramArr = self::getMethodParams($className);

return (new ReflectionClass($className))->newInstanceArgs($paramArr);

}

/**

* 执行类的方法

* @param [type] $className [类名]

* @param [type] $methodName [方法名称]

* @param [type] $params [额外的参数]

* @return [type] [description]

*/

public static function make($className, $methodName, $params = []) {

// 获取类的实例

$instance = self::getInstance($className);

// 获取该方法所需要依赖注入的参数

$paramArr = self::getMethodParams($className, $methodName);

return $instance->{$methodName}(...array_merge($paramArr, $params));

}

/**

* 获得类的方法参数,只获得有类型的参数

* @param [type] $className [description]

* @param [type] $methodsName [description]

* @return [type] [description]

*/

protected static function getMethodParams($className, $methodsName = '__construct') {

// 通过反射获得该类

$class = new ReflectionClass($className);

$paramArr = []; // 记录参数,和参数类型

// 判断该类是否有构造函数

if ($class->hasMethod($methodsName)) {

// 获得构造函数

$construct = $class->getMethod($methodsName);

// 判断构造函数是否有参数

$params = $construct->getParameters();

if (count($params) > 0) {

// 判断参数类型

foreach ($params as $key => $param) {

if ($paramClass = $param->getClass()) {

// 获得参数类型名称

$paramClassName = $paramClass->getName();

// 获得参数类型

$args = self::getMethodParams($paramClassName);

$paramArr[] = (new ReflectionClass($paramClass->getName()))->newInstanceArgs($args);

}

}

}

}

return $paramArr;

}

}

上面的代码使用php的反射函数,创建了一个容器类,使用该类来实现其他类的依赖注入功能。上面的依赖注入分为两种,一种是构造函数的依赖注入,一种是方法的依赖注入。 我们使用下面三个类来做下测试。

class A {

protected $cObj;

/**

* 用于测试多级依赖注入 B依赖A,A依赖C

* @param C $c [description]

*/

public function __construct(C $c) {

$this->cObj = $c;

}

public function aa() {

echo 'this is A->test';

}

public function aac() {

$this->cObj->cc();

}

}

class B {

protected $aObj;

/**

* 测试构造函数依赖注入

* @param A $a [使用引来注入A]

*/

public function __construct(A $a) {

$this->aObj = $a;

}

/**

* [测试方法调用依赖注入]

* @param C $c [依赖注入C]

* @param string $b [这个是自己手动填写的参数]

* @return [type] [description]

*/

public function bb(C $c, $b) {

$c->cc();

echo "\r\n";

echo 'params:' . $b;

}

/**

* 验证依赖注入是否成功

* @return [type] [description]

*/

public function bbb() {

$this->aObj->aac();

}

}

class C {

public function cc() {

echo 'this is C->cc';

}

}

测试构造函数的依赖注入:

// 使用Ioc来创建B类的实例,B的构造函数依赖A类,A的构造函数依赖C类。

$bObj = Ioc::getInstance('B');

$bObj->bbb(); // 输出:this is C->cc , 说明依赖注入成功。

// 打印$bObj

var_dump($bObj);

// 打印结果,可以看出B中有A实例,A中有C实例,说明依赖注入成功。

object(B)#3 (1) {

["aObj":protected]=>

object(A)#7 (1) {

["cObj":protected]=>

object(C)#10 (0) {

}

}

}

从上面两个例子可以看出我们创建对象或者调用方法时,根本就不用知道该类或该方法依赖了那个类。使用反射机制可以轻松的为我们自动注入所需要的类。

总结

其实只要熟悉php的反射机制,依赖注入并不难实现,上面的代码为了方便理解,所以写的简单除暴,在实际的项目中肯定不会这么简单,比如:会对注入的类和参数进行配置,比如会缓存实例化过的类,下次需要该类的实例时,可以直接使用,而不用在重新初始化等等。只要你原理了解了,其他的可以随着项目的需求自己去完善。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“Transaction rolled back because it has been marked as rollback-only”

spring的声明事务提供了强大功能,让我们把业务关注和非业务关注的东西又分离开了。好东西的使用,总是需要有代价的。使用声明事务的时候,一 个不小心经常会碰到“Transaction rolled back because it has been marked as rollback-only”这个…

c++获取时间戳_时间简史

好吧,我承认这篇文章有点标题党,本文内容与霍金同学同名书无任何相关,而是一篇不折不扣的关于时间和计算机程序的“时间简史”。时间是什么?数学家说时间是第四维度,不过显然计算机不这么看, 在计算机的世界…

cmake添加查找目录_CMakeLists.txt文件写法(7):添加查找头文件的路径

[1.List转换成为数组。(这里的List是实体是ArrayList)   调用ArrayList的toArray方法。  toArray  public T[] toArray(T[] a)返回一个按照正确的顺序包含此列表中INCLUDE_DIRECTORIES: Add include directories to the build.[ 最近在学习Linux下的C编程&…

[iOS] 建立与使用Framework

[iOS] 建立与使用Framework 前言 使用XCode开发iOS项目时,开发人员可以将可重用的程序代码,封装为Library或是Framework来提供其他开发人员使用。这两种封装方式在使用的时候:Library需要将.a封装档与所有公开的.h档提供给使用者加入项目&…

a标签点击事件_html常用标签

一、a标签作用&#xff1a;1、跳转到外部页面&#xff1b;2、跳转到内部锚点&#xff1b;3、跳转到邮箱或电话。属性&#xff1a;href&#xff08;hyperreference&#xff09;&#xff1a;超级引用、超级链接1、a的href的取值&#xff1a;<//http://google.com&#xff1a;无…

mysql导出表_mysql导出表的3种方式

文章转载自 &#xff1a;https://blog.csdn.net/jbb0403/article/details/26359573navicat导出表一共有三中用法&#xff1a;第一种&#xff1a;数据库上右键—>"转储SQL文件"&#xff0c;如图&#xff1a;"转储文件"是把整个数据库表全部导出&#xff…

Calculation控制台

接口 using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace susuusu {interface Interface1{int calculate(int a, int b,int c);} }加法类 using System; using System.Collections.Generic; using System.Linq; using System.Te…

网络资产管理系统_固定资产管理系统的常用操作

固定资产管理系统作为一个办公软件&#xff0c;能够帮助企业高效管理固定资产的日常事务。随着信息技术的发展和普及&#xff0c;越来越多的企业都开始使用固定资产管理系统&#xff0c;可是对于首次使用或者没有接触过固定资产管理系统的新手企业来说&#xff0c;对于系统的了…

mac mysql my.cnf_mac 增加 my.cnf

mac 增加 my.cnf发布时间&#xff1a;2018-04-25作者&#xff1a;laosun阅读(8133)mysql下没有my.cnf&#xff0c;如果想要修改一些配置还挺懵逼的&#xff0c;网上找了一些资料&#xff0c;经过博主亲测没有问题&#xff0c;发篇文章一为共享&#xff0c;二为做个备忘。博主使…

insert---插入记录

insert into table_name (column1,column2,.......) values(value1,value2,......); 例&#xff1a; insert into userinfo (name, sex, num) values(John, male, 100001 ); 说明&#xff1a; 1.column必须与value一一对应。 2.当对所有的字段添加数据时&#xff0c;(column1,…

python取前三位_Python 实现取多维数组第n维的前几位

Python 实现取多维数组第n维的前几位 现在我们有一个shape为(7352, 9, 128, 1)的numpy数组。 想要取出第2维的前三个数据&#xff0c;构成新数组(7352, 3, 128, 1) 我的思想是&#xff1a;将第2维数据转置&#xff08;transpose&#xff09;到第一维&#xff0c;再用切片&#…

solr 7 mysql导入_solr 7.7.0 windows 导入mysql数据库数据

接上一篇 准备导入数据首先修改hello/cong目录下的solrconfig.xml文件&#xff0c;添加如下节点&#xff1a;data-config.xml新建一个data-config.xml文件&#xff0c;与solrconfig.xml同一个目录下 添加数据库链接信息DataSource&#xff1a;数据库连接信息Entity&#xff1a;…

guava之cache

转自&#xff1a;http://ifeve.com/google-guava-cachesexplained/ 范例 01LoadingCache<Key, Graph> graphs CacheBuilder.newBuilder()02 .maximumSize(1000)03 .expireAfterWrite(10, TimeUnit.MINUTES)04 .removalListener(MY_LISTENER)05 …

access vba代码大全_VBA 实践指南 -- VBA连接各种数据库

ADO 简介ADO (ActiveX Data Objects&#xff0c;ActiveX数据对象&#xff09;是Microsoft提出的应用程序接口&#xff08;API&#xff09;用以实现访问关系或非关系数据库中的数据。例如&#xff0c;如果您希望编写应用程序从DB2或Oracle数据库中向网页提供数据&#xff0c;可以…

mysql savepoint语法_SAVEPOINT语法错误一例

前几天帮同事解决一个案例&#xff0c;在主从复制环境下&#xff0c;从库上的MySQL版本号是5.5.5&#xff0c;遇到下面的错误&#xff1a;~~~#其他非相关信息我都隐藏掉了[(yejrimysql.com)]> show slave status \G;Slave_IO_Running: YesSlave_SQL_Running: NoLast_Errno: …

方法的重载(overload)和重写(override)的区别

方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现&#xff0c;重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数&#xff0c;我们说该方法被重写 (Overriding)。子…

sql date类型_共享单车数据分析的SQL数据库设计

SQL&#xff0c;发音为“ sequel”(或SQL&#xff0c;如果愿意的话)&#xff0c;是数据科学家的重要工具。实际上&#xff0c;它可以说是获取数据工作中最重要的语言。在共享单车数据分析的SQL设计中&#xff0c;我们将从入门者的角度深入研究SQL基础知识&#xff0c;以使您入门…

mysql dodba_doDBA

doDBA tools是什么doDBA tools是一个基于控制台的远程监控工具&#xff0c;它不需要在本地/远程系统上安装任何软件&#xff0c;它可以实时收集操作系统、MySQL、InnoDB的实时性能状态数据&#xff0c;并可以生成Doing日志文件&#xff0c;来帮助你快速了解/优化系统及MySQL数据…

推荐几个配色和图标网站

图标网站https://www.iconfinder.comhttp://www.flaticon.com/ 渐变选择器http://sc.chinaz.com/jiaobendemo.aspx?downloadid1493221433405 在线配色器http://sc.chinaz.com/jiaobendemo.aspx?downloadid142815175416 安全颜色http://www.bootcss.com/p/websafecolors/ 转载…

python header头部请求_python3爬虫怎样构建请求header

写一个爬虫首先就是学会设置请求头header&#xff0c;这样才可以伪装成浏览器。下面小编我就来给大家简单分析一下python3怎样构建一个爬虫的请求头header。 1、python3跟2有了细微差别&#xff0c;所以我们先要引入request&#xff0c;python2没有这个request哦。然后复制网址…