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] ++;
}
}