X、数组$fdi['X]
 * - 初始化的途径:直接赋值、类名、匿名函数
 *
 * 
使用示例:
```
 *       $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  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] ++;
    }
}