php轻量级容器 进阶版 (支持惰性加载及自动运行)

使用方法见注释,直接上代码:

Di.php:

<?php
namespace util;
use util\DiMock;
class Di implements \ArrayAccess{
    private $_bindings = array();//服务列表
    private $_instances = array();//已经实例化的服务
    private $params = array();//预定义参数数组
    private $currentService;//当前正在设置的服务
    
    //获取服务
    public function get($name,$params=array()){
        $this->emptyCurrentService();
        
        //先从已经实例化的列表中查找
        if(isset($this->_instances[$name])){
            return $this->_instances[$name];
        }
        
        //检测有没有注册该服务
        if(!isset($this->_bindings[$name])){
            return null;
        }
        
        //生成服务
        $obj = $this->instanceBuild($name,$params);
        
        //如果是共享服务,则写入_instances列表,下次直接取回
        if($this->_bindings[$name]['shared'] == true && $obj){
            $this->_instances[$name] = $obj;
        }
        
        return $obj;
    }
    
    //构建实例
    private function instanceBuild($name,$params){
        $concrete = $this->_bindings[$name]['class'];//对象具体注册内容
        $reliantArguments = $this->_bindings[$name]['reliantArguments'];//设置的依赖
        $methodConfigList = $this->_bindings[$name]['methodConfigList'];//预设的方法调用集 的配置
        
        //匿名函数方式
        if($concrete instanceof \Closure){
            $obj = call_user_func_array($concrete,$params);
        }elseif(is_string($concrete)){//字符串方式      
            //若不带参数,则加载设置的依赖,将其作为默认参数
            if(empty($params)){
                $params = $this->loadReliantArguments($reliantArguments);
            }
            
            //若无依赖,直接生成目标对象
            if(empty($params)){
                $obj = new $concrete;
            }else{
                //带参数的类实例化,使用反射
                $class = new \ReflectionClass($concrete);
                
                //加载预处理的自定义参数
                $params = $this->loadParameter($params);
                
                //生成对象实例
                $obj = $class->newInstanceArgs($params);
            }
        }
        
        //运行预设的方法
        $this->invokeMethod($obj,$methodConfigList);
        
        return $obj;
    }
    
    
    //加载依赖,返回包含依赖实例的数组
    private function loadReliantArguments(Array $reliantArguments){
        $instance=array();
        foreach($reliantArguments as $argument ){
            if($argument instanceof DiMock){
                $config = $argument->getConcreteConfig();
                $instance[] = $this->get($config['name'],$config['params']);
            }else{
                $instance[] = $argument;
            }
        }
        
        return $instance;
    }
    
    //加载设置的预处理参数
    private function loadParameter($params){
        
        $newParams = array();
        foreach($params as $param ){
            if(is_string($param) && preg_match ("/%.*%/", $param)){
                $key = substr($param,1,strlen($param)-2);
                $this->replaceParameter($newParams,$key,$params);
            }else{
                $newParams[] = $param;
            }            
        }
        return $newParams;
    }
    
    //使用设置好的预处理参数值替换预处理参数
    private function replaceParameter(&$newParams,$key,$params){
        if(empty($this->params[$key])){
            $newParams[] = params;
        }else{
            $newParams[] = $this->params[$key];
        }
    }
    
    //调用预设的方法集
    private function invokeMethod($obj,$methodConfigList){
        foreach($methodConfigList as $config){
            //若未配置参数,直接运行
            if(empty($config['args'])){
                \call_user_func(array($obj,$config['name']));
            }else{
                //加载参数中依赖的对象
                $params = $this->loadReliantArguments($config['args']);
                
                //加载预处理的自定义参数
                $params = $this->loadParameter($params);
                
                \call_user_func_array(array($obj,$config['name']),$params);
            }
            
        }
    }
    
    //设置预处理参数的值
    public function setParameter($key, $val){
        $this->params[$key] = $val;
    }
    
    //检测是否已经绑定
    public function has($name){
        return isset($this->_bindings[$name]) or isset($this->_instances[$name]);
    }
    
    //卸载服务
    public function remove($name){
        $this->emptyCurrentService();
        unset($this->_bindings[$name],$this->_instances[$name]);
    }
    
    //置空正在设置的服务
    public function emptyCurrentService(){
        unset($this->currentService);
    }
    
    //设置服务
    public function set($name,$class){
        $this->_registerService($name, $class);
        return $this;
    }
    
    //设置共享服务
    public function setShared($name,$class){
        $this->_registerService($name, $class, true);
        return $this;
    }
    
    //注册服务
    private function _registerService($name,$class,$shared=false){
        $this->remove($name);
        $this->currentService = $name;
        if(!($class instanceof \Closure) && is_object($class)){
            $this->_instances[$name] = $class;
        }else{
            //Array(string:类名, bool:是否共享, array:依赖的参数, array:预调用的方法)
            $this->_bindings[$name] = array("class"=>$class,"shared"=>$shared,'reliantArguments'=>array(),'methodConfigList'=>array());
        }
    }
    
    //设置服务的依赖,$reliantArguments
    public function setArguments($reliantArguments=array()){
        $name = $this->currentService;
        if(!empty($this->_bindings[$name])){
            $this->_bindings[$name]['reliantArguments'] = $reliantArguments;
        }
        return $this;
    }
    
    //添加服务预设的方法调用,生成对象时自动运行该方法
    public function addMethodCall($methodName , Array $arguments=array()){
        $name = $this->currentService;
        if(!empty($this->_bindings[$name])){
            $methodConfig['name'] = $methodName;
            $methodConfig['args'] = $arguments;
            $this->_bindings[$name]['methodConfigList'][] = $methodConfig;
        }
        return $this;
    }
    
    //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);
    }
}

 

 

 

 

测试代码:

test.php

<?php
namespace util;

class Test{
    const A = 333;
    
    public static function s(){
        $di = new Di();
        
        //直接以类名方式注册
        $di->set('C','util\C');
        
        //B依赖于C
        $di->set('B','util\B');
        $di->setReliantClass('B',array(new DiMock('C')));
        
        //A依赖于B
        $di->set('A','util\A');
        $di->setReliantClass('A',array(new DiMock('B')));
        
        /* 设置好服务与依赖后即可直接获取服务,无需手动实例化,
        服务参数变化时再次设置后即可get新配置的服务 */
        $a=$di->get('A');
        $a->doSomething();
        echo '<br>';
        $b=$di->get('B');
        $b->doSomething();
        
        /* 结果为:
        util\C::doSomething我是C类|util\B::doSomething我是B类|
        util\C::doSomething我是C类|util\B::doSomething我是B类|util\A::doSomething我是A类| */

    }
     
}

class C
{
    public function doSomething()
    {
        echo __METHOD__, '我是C类|';
    }
}

class B
{
    private $c;

    public function __construct(C $c)
    {
        $this->c = $c;
    }

    public function doSomething()
    {
        $this->c->doSomething();
        echo __METHOD__, '我是B类|';
    }
}
class A
{
    private $b;

    public function __construct(B $b)
    {
        $this->b = $b;
    }

    public function doSomething()
    {
        $this->b->doSomething();
        echo __METHOD__, '我是A类|';;
    }
}

 

posted @ 2018-09-11 16:41  你怪哉  阅读(362)  评论(0)    收藏  举报