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类|';; } }

浙公网安备 33010602011771号