PHP写的一个轻量级的DI容器类(转)
理解什么是Di/IoC,依赖注入/控制反转。两者说的是一个东西,是当下流行的一种设计模式。大致的意思就是,准备一个盒子(容器),事先将项目中可能用到的类扔进去,在项目中直接从容器中拿,也就是避免了直接在项目中到处new,造成大量耦合。取而代之的是在项目类里面增设 setDi()和getDi()方法,通过Di同一管理类。 当然,以上内容并不是重点,详细的概念推荐参考这篇文章: http://docs.phalconphp.com/en/latest/reference/di.html 中文版: http://phalcon.5iunix.net/reference/di.html
<?php
class Di implements \ArrayAccess{
private $_bindings = array();//服务列表
private $_instances = array();//已经实例化的服务 //获取服务
public function get($name,$params=array()){
//先从已经实例化的列表中查找
if(isset($this->_instances[$name])){
return $this->_instances[$name];
} //检测有没有注册该服务
if(!isset($this->_bindings[$name])){
return null;
} $concrete = $this->_bindings[$name]['class'];//对象具体注册内容 $obj = null;
//匿名函数方式
if($concrete instanceof \Closure){
$obj = call_user_func_array($concrete,$params);
}
//字符串方式
elseif(is_string($concrete)){
if(empty($params)){
$obj = new $concrete;
}else{
//带参数的类实例化,使用反射
$class = new \ReflectionClass($concrete);
$obj = $class->newInstanceArgs($params);
}
}
//如果是共享服务,则写入_instances列表,下次直接取回
if($this->_bindings[$name]['shared'] == true && $obj){
$this->_instances[$name] = $obj;
} return $obj;
} //检测是否已经绑定
public function has($name){
return isset($this->_bindings[$name]) or isset($this->_instances[$name]);
} //卸载服务
public function remove($name){
unset($this->_bindings[$name],$this->_instances[$name]);
} //设置服务
public function set($name,$class){
$this->_registerService($name, $class);
} //设置共享服务
public function setShared($name,$class){
$this->_registerService($name, $class, true);
} //注册服务
private function _registerService($name,$class,$shared=false){
$this->remove($name);
if(!($class instanceof \Closure) && is_object($class)){
$this->_instances[$name] = $class;
}else{
$this->_bindings[$name] = array("class"=>$class,"shared"=>$shared);
}
} //ArrayAccess接口,检测服务是否存在
public function offsetExists($offset) {
return $this->has($offset);
} //ArrayAccess接口,以$di[$name]方式获取服务
public function offsetGet($offset) {
return $this->get($offset);
} //ArrayAccess接口,以$di[$name]=$value方式注册服务,非共享
public function offsetSet($offset, $value) {
return $this->set($offset,$value);
} //ArrayAccess接口,以unset($di[$name])方式卸载服务
public function offsetUnset($offset) {
return $this->remove($offset);
}
}
演示:
<?php
header("Content-Type:text/html;charset=utf8");
class A{
public $name;
public $age;
public function __construct($name=""){
$this->name = $name;
}
} include "Di.class.php";
$di = new Di();
//匿名函数方式注册一个名为a1的服务
$di->setShared('a1',function($name=""){
return new A($name);
});
//直接以类名方式注册
$di->set('a2','A');
//直接传入实例化的对象
$di->set('a3',new A("小唐")); $a1 = $di->get('a1',array("小李"));
echo $a1->name."<br/>";//小李
$a1_1 = $di->get('a1',array("小王"));
echo $a1->name."<br/>";//小李
echo $a1_1->name."<br/>";//小李 $a2 = $di->get('a2',array("小张"));
echo $a2->name."<br/>";//小张
$a2_1 = $di->get('a2',array("小徐"));
echo $a2->name."<br/>";//小张
echo $a2_1->name."<br/>";//小徐 $a3 = $di['a3'];//可以直接通过数组方式获取服务对象
echo $a3->name."<br/>";//小唐
通过set和setShared方式注册服务,支持 匿名函数,类名字符串,已经实例化的对象,两者的区别是:
set方式注册的,每次获取的时候都会重新实例化
setShared方式的,则只实例化一次,也就是所谓的单例模式
当然,对于直接注册已经实例化的对象,如上代码中的a3服务,set和setShared效果是一样的。
通过$di->get()获取服务,可接受两个参数,第一个参数是服务名,比如a1,a2,a3是必须的,第二个参数是一个数组,第二个参数会被当作匿名函数中的参数或者类构造函数里的参数传进去,参考call_user_func_array()。
删除服务则可以通过
unset($di['a1']);
or
$di->remove('a1');
判断是否包含一个服务可以通过
isset($di['a1']);
or
$di->has('a1');
PHP写的一个轻量级的DI容器类(转)的更多相关文章
- NET Core写了一个轻量级的Interception框架[开源]
NET Core写了一个轻量级的Interception框架[开源] ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只 ...
- 为了去重复,写了一个通用的比较容器类,可以用在需要比较的地方,且支持Lamda表达式
为了去重复,写了一个通用的比较容器类,可以用在需要比较的地方,且支持Lamda表达式,代码如下: public class DataComparer<T>:IEqualityCompare ...
- 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]
ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只是一个很轻量级的框架,但是在大部分情况下能够满足我们的需要.不过我觉得 ...
- 写的一个轻量级javascript框架的设计模式
公司一直使用jQuery框架,一些小的项目还是觉得jQuery框架太过于强大了,于是自己周末有空琢磨着写个自己的框架.谈到js的设计模式,不得不说说js的类继承机制,javascript不同于PHP可 ...
- 一个轻量级分布式RPC框架--NettyRpc
1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个轻量级的分布式RPC ...
- 一个轻量级分布式 RPC 框架 — NettyRpc
原文出处: 阿凡卢 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个 ...
- 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)
一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...
- **IOS:xib文件解析(xib和storyboard的比较,一个轻量级一个重量级)
使用Xcode做iOS项目,经常会和Xib文件打交道,因为Xib文件直观的展现出运行时视图的外观,所以上手非常容易,使用也很方便,但对于从未用纯代码写过视图的童鞋,多数对Xib的理解有些片面. Xib ...
- 开源自己写的一个拖拽库,兼容到IE8+
github地址:https://github.com/qiangzi7723/draggable 目前这个库的兼容做到了兼容IE8,所以如果需要兼容IE8的朋友不妨试试.库里面写了很多的注释,对于想 ...
随机推荐
- Android开发 Fragment中调用startActivityForResult返回错误的requestCode
返回错误的requestCode返回值为65537,在Fragment里调用startActivityForResult,就必须在Fragment里处理onActivityResult.
- ARGB和PARGB
原文链接: http://blog.csdn.net/lnwaycool/article/details/8610313 ARGB和PARGB是针对32位图像而言的,Windows下图像可以是1位.4 ...
- vc2010 属性值无效 灾难性故障 解决方法
原文链接: http://blog.csdn.net/enterlly/article/details/8739281 说明: 我遇到这个问题是这样的,在为某个类添加消息时出现的.因为该类不在此工程的 ...
- htmlentities、addslashes 、htmlspecialchars的使用
1.html_entity_decode():把html实体转换为字符. Eg:$str = "just atest & 'learn to use '";echo htm ...
- 人民币金额转化汉字的java写法
最近看到一个把一个浮点数转化为汉字人民币的小题,感觉很有意思就去用java实现了一下,没想到没有想得那么简单,在网上搜了一下也不近人意,经过几次修改后,现在实现了,现在分享一下. 一.当输入一个浮点数 ...
- JDK1.5新特性,基础类库篇,线程类(Thread)增强了哪些
java.lang.Thread类增强特性如下: 线程优先级已经更改.java.lang.Thread.MIN_PRIORITY = 1 java.lang.Thread.NORM_PRIORITY ...
- 学习排序算法(一):单文档方法 Pointwise
学习排序算法(一):单文档方法 Pointwise 1. 基本思想 这样的方法主要是将搜索结果的文档变为特征向量,然后将排序问题转化成了机器学习中的常规的分类问题,并且是个多类分类问题. 2. 方法流 ...
- 解决sweetalert 无故报错 elem.className.replace Uncaught TypeError: Cannot read property 'className' of null
今天碰到这么一个问题,在使用sweetalert的时候时有时无会报错 elem.className.replace Uncaught TypeError: Cannot read property ' ...
- ubuntu svn rabbitvcs 安装
参考链接:http://blog.csdn.net/weng_xianhu/article/details/10079179 32位系统完全按照上面链接安装没有问题,但是如果是64位系统,第六步下载资 ...
- 每日英语:The Invasion of the Online Tutors
It's a nightly dilemma in many households: A student hits a wall doing homework, and parents are too ...