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)”是一种编程技术,表述在面向对象编程中,可描述为在编译时静 ...
随机推荐
- Bootstrap3.3.7
页面的布局 <-!不让文字超出左右屏幕--> <style> .demo { word-wrap: break-word; } </style> 他们为那个模板中的 ...
- 算法与数据结构(一) 线性表的顺序存储与链式存储(Swift版)
温故而知新,在接下来的几篇博客中,将会系统的对数据结构的相关内容进行回顾并总结.数据结构乃编程的基础呢,还是要不时拿出来翻一翻回顾一下.当然数据结构相关博客中我们以Swift语言来实现.因为Swift ...
- docker发布netcore网站-零散记录
安装docker 安装Linux,使用云服务器或者虚拟机 参考:http://www.cnblogs.com/wangjieguang/p/hyper-v-ubuntu.html 系统更新 sudo ...
- 使用Python多渠道打包apk
使用Python生成多渠道包 往apk包中追加到一个空文件到META-INF目录以标识渠道,Android中获取此文件即可获得App的下载渠道 首先在info文件夹新建一个qdb.txt的空文本文件 ...
- Android开发之如何避免ANR(Keeping Your App Responsive)
一:什么是ANR 如果应用程序不能响应用户的输入了,那么就可以说应用ANR了. 如果需要运行一个耗时较长的操作的时候,不要把这个任务放在UI线程上运行,而是单独创建一个线程运行那些操作. 以下情况会出 ...
- 吴恩达机器学习笔记44-核函数(Kernels)
回顾我们之前讨论过可以使用高级数的多项式模型来解决无法用直线进行分隔的分类问题: 为了获得上图所示的判定边界,我们的模型可能是
- Eclipse 中构建 Maven 项目的完整过程 - 动态 Web 项目
进行以下步骤的前提是你已经安装好本地maven库和eclipse中的maven插件了(有的eclipse中已经集成了maven插件) 一.Maven项目的新建 1.鼠标右键---->New--- ...
- 第53节:Java当中的IO流(上)
Java当中的IO流 在Java中,字符串string可以用来操作文本数据内容,字符串缓冲区是什么呢?其实就是个容器,也是用来存储很多的数据类型的字符串,基本数据类型包装类的出现可以用来解决字符串和基 ...
- RocketMQ入门手册
前言 继我上一篇博客后 分布式消息队列RocketMQ学习教程① 上一篇博客最主要介绍了几种常用的MQ,所以本博客再简单介绍一下RocketMQ的原理和简单的例子,基于Java实现,希望可以帮助学习者 ...
- vue搭建多页面开发环境
自从习惯开发了单页面应用,对多页面的页面间的相互跳转间没有过渡效果.难维护极度反感.但是最近公司技术老大说,当一个应用越来越大的时候单页面模式应付不来,但是没讲怎么应付不来,所以还得自己去复习一遍这两 ...