理解什么是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. golang学习笔记 ----读写文件

    使用io/ioutil进行读写文件 ioutil包 其中提到了两个方法: func ReadFile func ReadFile(filename string) ([]byte, error) Re ...

  2. asp.net 浏览器下载文件的四种方式

    // 方法一:TransmitFile实现下载 protected void Button1_Click(object sender, EventArgs e) { Response.ContentT ...

  3. Internet上的WWW服务与HTTP协议(非常非常不错的文档,推荐订阅)

    Internet上的WWW服务与HTTP协议 兼容性----H1TP/1.1与HTTP/1.0后向兼容;运行1.1版本的web服务器可以与运行1.0版本的浏览器“对话”,运行1.1版本的浏览器也可以与 ...

  4. 在js中嵌套java代码

    jsp中有时候在js中操作某些java后台传递过来的数据逻辑比较复杂,比如list内容的遍历,可以直接在页面上添加java脚本来执行内容,代码如下: //在js中插入java代码操作 <% // ...

  5. java的跳转和重定向,加载显示层

    HttpServltRequest  req,   HttpDervletResponse resp 的 req.sendRedirect('页面');跳转到页面  浏览器地址跳转 --------- ...

  6. Android SDK不能够更新

    Adroid不能够更新,因为国内将google的服务器墙掉了,在 1) vim /etc/hosts(Windows上路径为:C:\Windows\System32\drivers\etc\hosts ...

  7. 关系型数据库性能测试参考指标----SQL Server

    注:以下指标取自SQL Server自身提供的性能计数器. [@more@] SQL Server 指标名称 指标描述 指标范围 指标单位 1.SQL Server中访问方法(Access Metho ...

  8. MySQL 5.6学习笔记(数据库基本操作,查看和修改表的存储引擎)

    1. 数据库基本操作 1.1  查看数据库 查看数据库列表: mysql> show databases; +--------------------+ | Database | +------ ...

  9. Android入门-新手如何成功创建一个Android小应用

    原文:http://android.eoe.cn/topic/summary 第一课程:Building Your First App [本课内容简介]欢迎加入到安卓应用的开发大潮中!这门课程会教授你 ...

  10. hdu-2045 递归

    #include <cstdio> #include <iostream> using namespace std; long long a[55] = {0,3,6}; lo ...