php的依赖注入容器
这里接着上一篇 php依赖注入,直接贴出完整代码如下:
<?php class C
{
public function doSomething()
{
echo __METHOD__, '我是C类|';
}
} class B
{
private $c; public function __construct(C $c)
{
$this->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类|
再来一段简单的代码演示一下,容器代码来自simple di container,完整如下:
<?php class C
{
public function doSomething()
{
echo __METHOD__, '我是C类|';
}
} class B
{
private $c; public function __construct(C $c)
{
$this->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)
下面的代码在Twittee的基础上,实现了Autowiring。
<?php
class C
{
public function doSomething()
{
echo __METHOD__, '我是周伯通C|';
}
} class B
{
private $c; public function __construct(C $c)
{
$this->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'php7'],则需用到[ArrayAccess(数组式访问)接口。
一些复杂的容器会有许多特性,欢迎博友们补充。
php的依赖注入容器的更多相关文章
- WPF PRISM开发入门二(Unity依赖注入容器使用)
这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点 ...
- Yii2.0 依赖注入(DI)和依赖注入容器的原理
依赖注入和依赖注入容器 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Serv ...
- YII框架的依赖注入容器与服务定位器简述
依赖注入容器 依赖注入(Dependency Injection,DI)容器就是一个对象use yii\di\Container,它知道怎样初始化并配置对象及其依赖的所有对象. 依赖注入和服务定位器都 ...
- 依赖注入容器Autofac的详解
Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成,并且开源,Autofac的主要特性如下: 1,灵活的组件实例化:Aut ...
- Unity轻量级依赖注入容器
一.前言 Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入.在Nuget里安装unity
- yii2之依赖注入与依赖注入容器
一.为什么需要依赖注入 首先我们先不管什么是依赖注入,先来分析一下没有使用依赖注入会有什么样的结果.假设我们有一个gmail邮件服务类GMail,然后有另一个类User,User类需要使用发邮件的功能 ...
- yii依赖注入和依赖注入容器
依赖注入和依赖注入容器¶ 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Ser ...
- .net core从依赖注入容器获取对象
创建引擎方法:该方法用于在不使用构造注入的情况下从依赖注入容器中获取对象 /// <summary> /// 一个负责创建对象的引擎 /// </summary> public ...
- IoC 依赖注入容器 Unity
原文:IoC 依赖注入容器 Unity IoC 是什么? 在软件工程领域,“控制反转(Inversion of Control,缩写为IoC)”是一种编程技术,表述在面向对象编程中,可描述为在编译时静 ...
随机推荐
- LeetCode刷题:第七题 整数翻转 第九题 回文数
第七题题目描述: 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入 ...
- 删除CSDN点击“阅读更多”按钮跳转到登录界面的功能
manifest.json { "manifest_version": 2, "name": "Helper2", "versio ...
- eclipse项目无故报错,markers信息为An error occurred while filtering resources
eclipse项目无故报错,markers信息为An error occurred while filtering resources 描述:eclipse项目和resource文件上有红色的叉,其m ...
- 1-C++的并发世界
1.1 何谓并发 并发的两种方式 多核机器上的真正并行 单核机器的任务切换 并发的两种途径 多进程并发 1.1 多进程并发需要通过操作系统进行进程间通信 多线程并发 2.1 多线程并发需要共享内存 1 ...
- centos7的Kubernetes部署记录
一.使用vm创建了三个centos系统,基本细节如下: 1.1 修改三台机器对应的主机名: [root@localhost ~] hostnamectl --static set-hostname k ...
- 背水一战 Windows 10 (107) - 通知(Toast): 提示音, 特定场景
[源码下载] 背水一战 Windows 10 (107) - 通知(Toast): 提示音, 特定场景 作者:webabcd 介绍背水一战 Windows 10 之 通知(Toast) 提示音 特定场 ...
- 面试官问我,Redis分布式锁如何续期?懵了。
前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...
- 电脑知识,一键开启Win10“超级性能模式”
现在主流系统以及从WIN7慢慢的转移到了WIN10,微软也为WIN10做了很多优化跟更新.今天要跟大家说的这个功能很多人肯定没有听说过.那就是WIN10的超级性能模式. 1. 大多数Win10是没有滴 ...
- vmware中nat模式中使用静态ip后无法上网的问题
在/etc/network/interfaces中添加静态ip auto eth0iface eth0 inet staticaddress 192.168.31.133netmask 255.255 ...
- Java 程序员必备的 15 个框架,前 3 个地位无可动摇!
Java 程序员方向太多,且不说移动开发.大数据.区块链.人工智能这些,大部分 Java 程序员都是 Java Web/后端开发.那作为一名 Java Web 开发程序员必须需要熟悉哪些框架呢? 今天 ...