colly_wyx
2018-05-18 50a53f7db63c5729b0ddbc93367117cf35ccf03c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<?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] ++;
    }
}