理解什么是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容器类(转)的更多相关文章

  1. NET Core写了一个轻量级的Interception框架[开源]

    NET Core写了一个轻量级的Interception框架[开源] ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只 ...

  2. 为了去重复,写了一个通用的比较容器类,可以用在需要比较的地方,且支持Lamda表达式

    为了去重复,写了一个通用的比较容器类,可以用在需要比较的地方,且支持Lamda表达式,代码如下: public class DataComparer<T>:IEqualityCompare ...

  3. 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]

    ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只是一个很轻量级的框架,但是在大部分情况下能够满足我们的需要.不过我觉得 ...

  4. 写的一个轻量级javascript框架的设计模式

    公司一直使用jQuery框架,一些小的项目还是觉得jQuery框架太过于强大了,于是自己周末有空琢磨着写个自己的框架.谈到js的设计模式,不得不说说js的类继承机制,javascript不同于PHP可 ...

  5. 一个轻量级分布式RPC框架--NettyRpc

    1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个轻量级的分布式RPC ...

  6. 一个轻量级分布式 RPC 框架 — NettyRpc

    原文出处: 阿凡卢 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个 ...

  7. 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)

    一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...

  8. **IOS:xib文件解析(xib和storyboard的比较,一个轻量级一个重量级)

    使用Xcode做iOS项目,经常会和Xib文件打交道,因为Xib文件直观的展现出运行时视图的外观,所以上手非常容易,使用也很方便,但对于从未用纯代码写过视图的童鞋,多数对Xib的理解有些片面. Xib ...

  9. 开源自己写的一个拖拽库,兼容到IE8+

    github地址:https://github.com/qiangzi7723/draggable 目前这个库的兼容做到了兼容IE8,所以如果需要兼容IE8的朋友不妨试试.库里面写了很多的注释,对于想 ...

随机推荐

  1. ACM 马拦过河卒(动态规划)

    解题思路: 用一个二维数组a[i][j]标记 马的位置和马的跳点(统称控制点)该位置=1: 再用一个二维数组f[i][j]表示行进的位置,如果前一行的当前列不是马的控制点,或者前一列的当前行不是马的控 ...

  2. centos 搭建gitlab

    #修改yum源 yum -y install wget cd /etc/yum.repos.d wget -O CentOS-Base.repo http://mirrors.aliyun.com/r ...

  3. adb命令大全「含shell和wait-for-devices等」

    adb shell 大全: http://adbshell.com/commands 下列表格列出了adb常见命令,注意,它并不是只有adb shell,shell只是其中一个. Category C ...

  4. Maven打包web工程成WAR

    其实不一定要通过Goals:package来打war包,直接run as maven bulid也行:

  5. pywinauto如何获取gridwindow控件的屏幕位置

    一:问题描述 问题一:通过查找pywinauto在线文档,其中没有讲解到gridwindow控件的方法,我不知道这个控件是不是标准控件,还是pywinauto根本就没适配这个控件.从网上查询了好多资料 ...

  6. 全世界只有我们Erlang程序员是正确的

    http://www.aqee.net/erlang-solving-the-wrong-problem/ 对某些程序来说是的,但对大多数程序来说不是.对大多数程序来说24个CPU中只有一个被利用.C ...

  7. iOS Xcode制作模板类-b

    为什么要定义模板类 遵守代码规范可以提高代码可读性, 降低后期维护成本. 当我们定下了一个团队都认同的代码规范, 如我们要求所有的viewController的代码都得按照下面来组织: #pragma ...

  8. Little Kings - SGU 223(状态压缩)

    题目大意:在一个N*N的棋盘上放置M个国王,已知国王会攻击与它相邻的8个格子,要求放置的额国王不能相互攻击,求放置的方式有多少种. 分析:用dp[row][state][nOne],表示本行状态sta ...

  9. Hibernate三种状态及生命周期

    临时状态---使用new操作符的对象不能立刻持久,也就是说没有任何跟数据库相关的行为, 只要应用不再使用这些对象,状态会丢失,并由垃圾回收机制回收持久对象---持久实例是具有数据库标识的实例.统一又S ...

  10. PLSQL(1)

      PLSQLl编程                       plsql是Oracle在标准的sql语言上的扩展 特点:可以在数据库中定义变量,常量,还可以使用条件语句和判断语句以及异常等   P ...