博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
php的依赖注入容器
阅读量:7043 次
发布时间:2019-06-28

本文共 5493 字,大约阅读时间需要 18 分钟。

这里接着上一篇 ,直接贴出完整代码如下:

c = $c; } public function doSomething() { $this->c->doSomething(); echo __METHOD__, '我是B类|'; }}class A{ private $b; public function __construct(B $b) { $this->b = $b; } public function doSomething() { $this->b->doSomething(); echo __METHOD__, '我是A类|';; }} //这段代码使用了,在给不可访问属性赋值时,__set() 会被调用。读取不可访问属性的值时,__get() 会被调用。class Container{ private $s = array(); function __set($k, $c) { $this->s[$k] = $c; } function __get($k) { return $this->s[$k]($this); }} $class = new Container();$class->c = function () { return new C();};$class->b = function ($class) { return new B($class->c);};$class->a = function ($class) { return new A($class->b);};// 从容器中取得A$model = $class->a;$model->doSomething(); // C::doSomething我是C类|B::doSomething我是B类|A::doSomething我是A类|

再来一段简单的代码演示一下,容器代码来自,完整如下:

c = $c; } public function doSomething() { $this->c->doSomething(); echo __METHOD__, '我是B类|'; }}class A{ private $b; public function __construct(B $b) { $this->b = $b; } public function doSomething() { $this->b->doSomething(); echo __METHOD__, '我是A类|';; }}class IoC{ protected static $registry = []; public static function bind($name, Callable $resolver) { static::$registry[$name] = $resolver; } public static function make($name) { if (isset(static::$registry[$name])) { $resolver = static::$registry[$name]; return $resolver(); } throw new Exception('Alias does not exist in the IoC registry.'); }}IoC::bind('c', function () { return new C();});IoC::bind('b', function () { return new B(IoC::make('c'));});IoC::bind('a', function () { return new A(IoC::make('b'));});// 从容器中取得A$foo = IoC::make('a');$foo->doSomething(); // C::doSomething我是C类|B::doSomething我是B类|A::doSomething我是A类|

这段代码使用了

依赖注入容器的高级功能

真实的dependency injection container会提供更多的特性,如

  • 自动绑定(Autowiring)或 自动解析(Automatic Resolution)

  • 注释解析器(Annotations)

  • 延迟注入(Lazy injection)

下面的代码在的基础上,实现了Autowiring。

c = $c; } public function doSomething() { $this->c->doSomething(); echo __METHOD__, '我是周伯通B|'; }}class A{ private $b; public function __construct(B $b) { $this->b = $b; } public function doSomething() { $this->b->doSomething(); echo __METHOD__, '我是周伯通A|';; }}class Container{ private $s = array(); public function __set($k, $c) { $this->s[$k] = $c; } public function __get($k) { // return $this->s[$k]($this); return $this->build($this->s[$k]); } /** * 自动绑定(Autowiring)自动解析(Automatic Resolution) * * @param string $className * @return object * @throws Exception */ public function build($className) { // 如果是匿名函数(Anonymous functions),也叫闭包函数(closures) if ($className instanceof Closure) { // 执行闭包函数,并将结果 return $className($this); } /** @var ReflectionClass $reflector */ $reflector = new ReflectionClass($className); // 检查类是否可实例化, 排除抽象类abstract和对象接口interface if (!$reflector->isInstantiable()) { throw new Exception("Can't instantiate this."); } /** @var ReflectionMethod $constructor 获取类的构造函数 */ $constructor = $reflector->getConstructor(); // 若无构造函数,直接实例化并返回 if (is_null($constructor)) { return new $className; } // 取构造函数参数,通过 ReflectionParameter 数组返回参数列表 $parameters = $constructor->getParameters(); // 递归解析构造函数的参数 $dependencies = $this->getDependencies($parameters); // 创建一个类的新实例,给出的参数将传递到类的构造函数。 return $reflector->newInstanceArgs($dependencies); } /** * @param array $parameters * @return array * @throws Exception */ public function getDependencies($parameters) { $dependencies = []; /** @var ReflectionParameter $parameter */ foreach ($parameters as $parameter) { /** @var ReflectionClass $dependency */ $dependency = $parameter->getClass(); if (is_null($dependency)) { // 是变量,有默认值则设置默认值 $dependencies[] = $this->resolveNonClass($parameter); } else { // 是一个类,递归解析 $dependencies[] = $this->build($dependency->name); } } return $dependencies; } /** * @param ReflectionParameter $parameter * @return mixed * @throws Exception */ public function resolveNonClass($parameter) { // 有默认值则返回默认值 if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } throw new Exception('I have no idea what to do here.'); }}// ----$class = new Container();$class->b = 'B';$class->a = function ($class) { return new A($class->b);};// 从容器中取得A$model = $class->a;$model->doSomething(); $di = new Container();$di->php7 = 'A';/** @var A $php7 */$foo = $di->php7;var_dump($foo);$foo->doSomething(); //C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|object(A)#10 (1) { ["b":"A":private]=> object(B)#14 (1) { ["c":"B":private]=> object(C)#16 (0) { } } } C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|?>

以上代码的原理参考PHP官方文档:,PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。

若想进一步提供一个数组访问接口,如$di->php7可以写成$di。

一些复杂的容器会有许多特性,欢迎博友们补充。

 

转载地址:http://jeqal.baihongyu.com/

你可能感兴趣的文章
剥开比原看代码09:通过dashboard创建密钥时,前端的数据是如何传到后端的?
查看>>
180710-MySql插入唯一键冲突的三种可选方式
查看>>
数据库两个神器【索引和锁】
查看>>
金9银10,分享几个重要的Android面试题
查看>>
Spring Boot 2.0.2 参考指南(通用的应用程序属性 ②)中文文档
查看>>
sysbench基准测试
查看>>
决策树
查看>>
Spring Cloud Config采用数据库存储配置内容
查看>>
刨根问底ajax原理与封装
查看>>
关于部署CI/CD的5点建议
查看>>
每天学点Python Cookbook(五)
查看>>
antd-pro添加新页面和新功能
查看>>
ES6 解构赋值
查看>>
交互搜索中的自然语言理解技术
查看>>
ListView vs FlatList性能对比
查看>>
java并发编程学习20--基于springboot的秒杀系统实现2--redis缓存
查看>>
Hybris UI的Route(路由)实现
查看>>
小程序开发之一(使用fly进行http封装)
查看>>
freebsd 镜像重新挂载数据盘
查看>>
Canvas基础知识(一)
查看>>