文档章节

PHP写的一个轻量级的DI容器类

吾爱
 吾爱
发布于 2014/04/28 14:41
字数 944
阅读 2486
收藏 16

直接上代码吧.

Di容器类:

<?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');

就这么多了。



© 著作权归作者所有

吾爱
粉丝 142
博文 272
码字总数 91680
作品 0
后端工程师
私信 提问
加载中

评论(2)

wintercode
wintercode
在下部分程序语句的24行
$a1_1 = $di->get('a1',array("小王"));
echo $a1->name."<br/>";//小李
echo $a1_1->name."<br/>";//小李
为什么输出的是"小李",而不是"小王"呢?
f
fifsky
不错
对依赖注入和控制反转的一点理解

1.1、IoC是什么 Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制...

舒小贱
2017/12/06
0
0
【半小时大话.net依赖注入】(一)理论基础+实战控制台程序实现AutoFac注入

系列目录 第一章|理论基础+实战控制台程序实现AutoFac注入 第二章|AutoFac的常见使用套路 第三章|实战Asp.Net Framework Web程序实现AutoFac注入 第四章|实战Asp.Net Core自带DI实现依赖注入...

在7楼
07/08
0
0
依赖注入的简单记录

想理解php依赖注入和控制反转两个概念,就必须搞清楚如下的问题: DI——Dependency Injection 依赖注入 IoC——Inversion of Control 控制反转 1、参与者都有谁?  IOC/DI容器就是一个全局...

金于虎
2016/12/23
25
1
谈谈PHP实现依赖注入(控制反转)

首先我们抛开那玄乎其神的定义,我们先从一个场景入手。 假设我们有两个类:class A 和 class B,以下简称A和B; 现在我们要使用A,而A依赖了B,A的构造如下: class A{ private $b; public ...

吾爱
2015/11/20
1K
2
菜菜鸟Zend Framework 2 不完全学习涂鸦(十三)-- 学习依赖注入

学习依赖注入 一、非常简短的介绍 Di(Dependency Injection) 依赖注入(Dependency Injection)是一个已经在 web 界讨论很多次的概念。这里的快速入门以此为目的,我们通过以下简单的代码解...

Jacky.Wang
2013/08/23
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

sync 包讲解

sync.Once Once 的作用是多次调用但只执行一次,Once 只有一个方法,Once.Do(),向 Do 传入一个函数,这个函数在第一次执行 Once.Do() 的时候会被调用,以后再执行 Once.Do() 将没有任何动作...

李琼涛
12分钟前
3
0
java中的byte占一字节或4字节

https://www.jianshu.com/p/2f663dc820d0

南桥北木
26分钟前
2
0
Cassandra 常用命令

Linux控制台命令 #进入Cassandra的安装目录 cd /home/db/cassandra/cassandra #进入Cassandra 无密码 ./bin/cqlsh localhost(IP)有密码 ./bin/cqlsh localhost(IP)-u 用户名 #显示所...

最菜最菜之小菜鸟
31分钟前
4
0
自建redis笔记

自建redis笔记 最近在linux安装了一下redis,特做一些笔记! 本文先单节点启动redis,然后再进行持久化配置,在次基础上,再分享搭建主从模式的配置以及Sentinel 哨兵模式及集群的搭建 单节点...

北极之北
39分钟前
3
0
扛住阿里双十一高并发流量,Sentinel是怎么做到的?

Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景 本文介绍阿里开源限流熔断方案Sentinel功能、原理、架构、快速入门以及相关框架比较 基本介绍 1 名词解释 服务限流 :当系统资源...

分布式系统架构
46分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部