理解什么是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. C# 对文件与文件夹的操作包括删除、移动与复制

    在.Net中,对文件(File)和文件夹(Folder)的操作可以使用File类和Directory类,也可以使用FileInfo类和DirectoryInfo类.文件夹(Folder)是只在Wind ...

  2. 【转载】使用 Google Guava 美化你的 Java 代码

    转载地址: https://blog.csdn.net/wisgood/article/details/13297535 原文地址:https://my.oschina.net/leejun2005/ ...

  3. Android 获取闹钟引发的血案

    想做一个锁屏的软件.锁屏后可以显示闹钟信息. 一开始的思路是通过android content provider获取 mActivityObject.getContentResolver().quer ...

  4. robotframework + appium 获取android toast

    android toast 获取主要方式是在出现toast的时候查找元素:xpath=//*[contains(@text,'记同步')]  ,该xpath 表示为toast信息含有  "记 ...

  5. flask中路由的本质源码分析

    flask中url的本质: 吧url和视图函数封装到一个Rule对象里面去了,并且吧这个对象添加到url_map中 Rule={"url":'/index','method':'i ...

  6. 怎么部署 .NET Core Web项目 到linux

    .NET Core is free, open source, cross platform and runs basically everywhere. STEP 0 - GET A CHEAP H ...

  7. Nginx(四):压缩功能详解

    gzip (GNU-ZIP) 是一种压缩技术.经过 gzip 压缩后页面大小可以变为原来的 30%甚至更小. 这样,用户浏览页面的时候速度会快得多.  gzip 的压缩页面需要浏览器和服务器双方都支持 ...

  8. yum 完全卸载依赖

    实例:安装rabbitmq-server # yum history list rabbitmq-server Loaded plugins: fastestmirror ID | Login use ...

  9. HTML5学习笔记(十六):原型、类和继承【JS核心知识点】

    理解原型 在JavaScript中,只要声明了一个函数,就会为该函数创建一个名为prototype的属性,该属性指向当前函数的原型对象. 而函数的原型对象有一个constructor属性,该属性指向刚 ...

  10. RequestDispatcher.forward和HttpServletResponse.sendRedirect

    (1)RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件:而HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程 ...