| <?php | 
| /** | 
|  * PhalApi_DI 依赖注入类 | 
|  * | 
|  *  Dependency Injection 依赖注入容器 | 
|  *   | 
|  * - 调用的方式有:set/get函数、魔法方法setX/getX、类变量$fdi->X、数组$fdi['X] | 
|  * - 初始化的途径:直接赋值、类名、匿名函数 | 
|  * | 
|  * <br>使用示例:<br> | 
| ``` | 
|  *       $di = new PhalApi_DI(); | 
|  *       | 
|  *       // 用的方式有:set/get函数  魔法方法setX/getX、类属性$di->X、数组$di['X'] | 
|  *       $di->key = 'value'; | 
|  *       $di['key'] = 'value'; | 
|  *       $di->set('key', 'value'); | 
|  *       $di->setKey('value'); | 
|  *       | 
|  *       echo $di->key; | 
|  *       echo $di['key']; | 
|  *       echo $di->get('key'); | 
|  *       echo $di->getKey(); | 
|  *       | 
|  *       // 初始化的途径:直接赋值、类名(会回调onInitialize函数)、匿名函数 | 
|  *       $di->simpleKey = array('value'); | 
|  *       $di->classKey = 'PhalApi_DI'; | 
|  *       $di->closureKey = function () { | 
|  *            return 'sth heavy ...'; | 
|  *       }; | 
| ```        | 
|  *       | 
|  * @property PhalApi_Request        $request    请求 | 
|  * @property PhalApi_Response_Json  $response   结果响应 | 
|  * @property PhalApi_Cache          $cache      缓存 | 
|  * @property PhalApi_Crypt          $crypt      加密 | 
|  * @property PhalApi_Config         $config     配置 | 
|  * @property PhalApi_Logger         $logger     日记 | 
|  * @property PhalApi_DB_NotORM      $notorm     数据库 | 
|  * @property PhalApi_Loader         $loader     自动加载 | 
|  * @property PhalApi_Helper_Tracer  $tracer     全球追踪器 | 
|  *  | 
|  * @package     PhalApi\DI | 
|  * @link        http://docs.phalconphp.com/en/latest/reference/di.html 实现统一的资源设置、获取与管理,支持延时加载 | 
|  * @license     http://www.phalapi.net/license GPL 协议 | 
|  * @link        http://www.phalapi.net/ | 
|  * @author      dogstar <chanzonghuang@gmail.com> 2014-01-22 | 
|  */  | 
|   | 
| class PhalApi_DI implements ArrayAccess { | 
|   | 
|     /** | 
|      * @var PhalApi_DI $instance 单例 | 
|      */ | 
|     protected static $instance = NULL; | 
|   | 
|     /** | 
|      * @var array $hitTimes 服务命中的次数 | 
|      */ | 
|     protected $hitTimes = array(); | 
|      | 
|     /** | 
|      * @var array 注册的服务池 | 
|      */ | 
|     protected $data = array(); | 
|   | 
|     public function __construct() { | 
|   | 
|     } | 
|   | 
|     /** | 
|      * 获取DI单体实例 | 
|      * | 
|      * - 1、将进行service级的构造与初始化 | 
|      * - 2、也可以通过new创建,但不能实现service的共享 | 
|      */  | 
|     public static function one() { | 
|         if (static::$instance == NULL) { | 
|             static::$instance = new PhalApi_DI(); | 
|             static::$instance->onConstruct(); | 
|         } | 
|   | 
|         return static::$instance; | 
|     } | 
|   | 
|     /** | 
|      * service级的构造函数 | 
|      * | 
|      * - 1、可实现一些自定义业务的操作,如内置默认service | 
|      * - 2、首次创建时将会调用 | 
|      */  | 
|     public function onConstruct() { | 
|         $this->request = 'PhalApi_Request'; | 
|         $this->response = 'PhalApi_Response_Json'; | 
|         $this->tracer = 'PhalApi_Helper_Tracer'; | 
|     } | 
|   | 
|     public function onInitialize() { | 
|     } | 
|   | 
|     /** | 
|      * 统一setter | 
|      * | 
|      * - 1、设置保存service的构造原型,延时创建 | 
|      * | 
|      * @param string $key service注册名称,要求唯一,区分大小写 | 
|      * @parms mixed $value service的值,可以是具体的值或实例、类名、匿名函数、数组配置 | 
|      */  | 
|     public function set($key, $value) { | 
|         $this->resetHit($key); | 
|   | 
|         $this->data[$key] = $value; | 
|   | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 统一getter | 
|      * | 
|      * - 1、获取指定service的值,并根据其原型分不同情况创建 | 
|      * - 2、首次创建时,如果service级的构造函数可调用,则调用 | 
|      * - 3、每次获取时,如果非共享且service级的初始化函数可调用,则调用 | 
|      * | 
|      * @param string $key service注册名称,要求唯一,区分大小写 | 
|      * @param mixed $default service不存在时的默认值 | 
|      * @param boolean $isShare 是否获取共享service | 
|      * @return mixed 没有此服务时返回NULL | 
|      */  | 
|     public function get($key, $default = NULL) { | 
|         if (!isset($this->data[$key])) { | 
|             $this->data[$key] = $default; | 
|         } | 
|   | 
|         $this->recordHitTimes($key); | 
|   | 
|         if ($this->isFirstHit($key)) { | 
|             $this->data[$key] = $this->initService($this->data[$key]); | 
|         } | 
|   | 
|         return $this->data[$key]; | 
|     } | 
|   | 
|     /** ------------------ 魔法方法 ------------------ **/ | 
|   | 
|     public function __call($name, $arguments) { | 
|         if (substr($name, 0, 3) == 'set') { | 
|             $key = lcfirst(substr($name, 3)); | 
|             return $this->set($key, isset($arguments[0]) ? $arguments[0] : NULL); | 
|         } else if (substr($name, 0, 3) == 'get') { | 
|             $key = lcfirst(substr($name, 3)); | 
|             return $this->get($key, isset($arguments[0]) ? $arguments[0] : NULL); | 
|         } | 
|   | 
|         throw new PhalApi_Exception_InternalServerError( | 
|             T('Call to undefined method PhalApi_DI::{name}() .', array('name' => $name)) | 
|         ); | 
|     } | 
|   | 
|     public function __set($name, $value) { | 
|         $this->set($name, $value); | 
|     } | 
|   | 
|     public function __get($name) { | 
|         return $this->get($name, NULL); | 
|     } | 
|   | 
|     /** ------------------ ArrayAccess(数组式访问)接口 ------------------ **/ | 
|   | 
|     public function offsetSet($offset, $value) { | 
|         $this->set($offset, $value); | 
|     } | 
|   | 
|     public function offsetGet($offset) { | 
|         return $this->get($offset, NULL); | 
|     } | 
|   | 
|     public function offsetUnset($offset) { | 
|         unset($this->data[$offset]); | 
|     } | 
|   | 
|     public function offsetExists($offset) { | 
|         return isset($this->data[$offset]); | 
|     } | 
|   | 
|     /** ------------------ 内部方法 ------------------ **/ | 
|   | 
|     protected function initService($config) { | 
|         $rs = NULL; | 
|   | 
|         if ($config instanceOf Closure) { | 
|             $rs = $config(); | 
|         } elseif (is_string($config) && class_exists($config)) { | 
|             $rs = new $config(); | 
|             if(is_callable(array($rs, 'onInitialize'))) { | 
|                 call_user_func(array($rs, 'onInitialize')); | 
|             } | 
|         } else { | 
|             $rs = $config; | 
|         } | 
|   | 
|         return $rs; | 
|     } | 
|   | 
|     protected function resetHit($key) { | 
|         $this->hitTimes[$key] = 0; | 
|     } | 
|   | 
|     protected function isFirstHit($key) { | 
|         return $this->hitTimes[$key] == 1; | 
|     } | 
|   | 
|     protected function recordHitTimes($key) { | 
|         if (!isset($this->hitTimes[$key])) { | 
|             $this->hitTimes[$key] = 0; | 
|         } | 
|   | 
|         $this->hitTimes[$key] ++; | 
|     } | 
| } |