PHP利用反射实现依赖注入

9 篇文章 0 订阅

本文参考博客(https://blog.csdn.net/dream_successor/article/details/79078905, https://www.cnblogs.com/i6010/articles/10559630.html),非常感谢原博主.为了加深理解,做了部分修改,增加了适当注释.
前一篇简单理解了PHP依赖注入,在实际开发过程中,我们并不知道依赖的类将来会扩展成什么样子,因此我们需要在实现依赖注入的时候,通过容器利用PHP反射类去实现. 这里的容器其实就是一个能通过反射类实现依赖注入,并且最终返回我们需要的实例的类.
大致实现思路: 在这里插入图片描述
以下是示例代码,
创建 test.php:

<?php
//设置三个有依赖关系的类: A依赖B,B依赖C
class C {
	public function test(){
		echo __CLASS__.'<br>';
	}
}
class B {
	private $c;
	public function __construct(C $c){
		$this->c = $c;
	}
	public function test(){
		$this->c->test();
		echo __CLASS__.'<br>';
	}
}
class A {
	private $b;
	public function __construct(B $b){
		$this->b = $b;
	}
	public function test(){
		$this->b->test();
		echo __CLASS__.'<br>';
	}
}

创建容器类container.php

<?php
	class Container {		
		private $repository = []; 
		public function __set($name,$value){
			$this->repository[$name] = $value;
		}
		public function __get($name){
			if(isset($this->repository[$name])){
				return $this->build($this->repository[$name]);
			}
			throw new Exception($name.'is not exist in the repository');			
		}
		/**
		 *创建类的实例,并注入依赖
		 *@param $name string 类名
		 *@return object 返回类的实例
		 */
		public function build($name){
			//如果是匿名函数,直接返回执行结果
			if($name instanceof Closure){
				return $name($this);
			}
			//通过反射获取类的内部结构,实例化类
			$reflector = new ReflectionClass($name);
			//检查类是否可以实例化, 排除抽象类, 接口
			if(!$reflector->isInstantiable()){
				throw new Exception('类不能实例化');
			}
			//获取类的构造函数
			$constructor = $reflector->getConstructor();
			//若无构造函数,说明被依赖类中没有再依赖其他类,直接返回实例化对象
			if(is_null($constructor)){
				return new $name;
			}
			//获取构造函数参数,返回参数列表数组
			$parameters = $constructor->getParameters();
			//递归解析参数,获取依赖的参数或者依赖类的对象
			$dependencies = $this->getDependencies($parameters);
			//创建类的实例,将递归解析获取的参数传递到构造函数
			return $reflector->newInstanceArgs($dependencies);
		}
		/**
		 *获取依赖的类
		 *@param $parameters array 构造函数的参数列表数组
		 *@return array 返回由依赖类的实例和构造函数普通参数的默认值组成的数组
		 */
		public function getDependencies($parameters){
			$dependencies = [];
			foreach($parameters as $parameter){
				$dependency = $parameter->getClass();
				if(is_null($dependency)){//参数不是一个类,获取默认值
					$dependencies[] = $this->resolveNonClass($parameter);
				}else{//是一个类, 递归解析
					$dependencies[] = $this->build($parameter->name);
				}
			}			
			return $dependencies; 
		}
		/**
		 *获取构造函数参数的默认值
		 *@param $parameter 
		 *@return 返回构造函数参数默认的值
		 */
		public function resolveNonClass($parameter){
			//如果有默认值则返回
			if($parameter->isDefaultValueAvailable()){
				return $parameter->getDefaultValue();
			}
			throw new Exception('');
		}
	}

在test.php中引入container类并使用依赖注入:

<?php
...
require_once './container.php';
$container = new Container;
$container->a = 'A';  
$a = $container->a;  //创建A类的实例, 并自动注入依赖. 
$a->test(); // 输出 C B A
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值