Passed
Push — master ( 86fa88...ed1da9 )
by teng
01:20
created
src/poker/application/WebApplication.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -12,11 +12,11 @@
 block discarded – undo
12 12
  */
13 13
 class WebApplication extends AbstractApplication
14 14
 {
15
-	/**
16
-	 * {@inheritdoc}
17
-	 */
18
-	public function run(): void
19
-	{
15
+    /**
16
+     * {@inheritdoc}
17
+     */
18
+    public function run(): void
19
+    {
20 20
 
21
-	}
21
+    }
22 22
 }
Please login to merge, or discard this patch.
src/poker/application/AbstractApplication.php 1 patch
Indentation   +61 added lines, -61 removed lines patch added patch discarded remove patch
@@ -18,74 +18,74 @@
 block discarded – undo
18 18
  */
19 19
 abstract class AbstractApplication
20 20
 {
21
-	/**
22
-	 * 应用程序实例
23
-	 *
24
-	 * @var \poker\application\AbstractApplication
25
-	 */
26
-	protected static $instance;
21
+    /**
22
+     * 应用程序实例
23
+     *
24
+     * @var \poker\application\AbstractApplication
25
+     */
26
+    protected static $instance;
27 27
 
28
-	/**
29
-	 * 应用程序开始时间
30
-	 *
31
-	 * @var float
32
-	 */
33
-	protected $startTime;
28
+    /**
29
+     * 应用程序开始时间
30
+     *
31
+     * @var float
32
+     */
33
+    protected $startTime;
34 34
 
35
-	/**
36
-	 * 应用程序根路径地址
37
-	 *
38
-	 * @var string
39
-	 */
40
-	protected $rootPath;
35
+    /**
36
+     * 应用程序根路径地址
37
+     *
38
+     * @var string
39
+     */
40
+    protected $rootPath;
41 41
 
42
-	/**
43
-	 * 容器实例
44
-	 *
45
-	 * @var \poker\container\Container
46
-	 */
47
-	protected $container;
42
+    /**
43
+     * 容器实例
44
+     *
45
+     * @var \poker\container\Container
46
+     */
47
+    protected $container;
48 48
 
49
-	/**
50
-	 * 构造函数
51
-	 *
52
-	 * @param string $rootPath 应用程序根路径地址
53
-	 */
54
-	public function __construct(string $rootPath)
55
-	{
56
-		$this->startTime = microtime(true);
57
-		$this->rootPath  = rtrim($rootPath, '\\/');
58
-		$this->container = Container::getInstance();
49
+    /**
50
+     * 构造函数
51
+     *
52
+     * @param string $rootPath 应用程序根路径地址
53
+     */
54
+    public function __construct(string $rootPath)
55
+    {
56
+        $this->startTime = microtime(true);
57
+        $this->rootPath  = rtrim($rootPath, '\\/');
58
+        $this->container = Container::getInstance();
59 59
 
60
-		// 应用程序初始化
61
-		$this->initialize();
62
-	}
60
+        // 应用程序初始化
61
+        $this->initialize();
62
+    }
63 63
 
64
-	/**
65
-	 * 返回应用程序实例
66
-	 *
67
-	 * @param  string                                 $rootPath 应用程序根路径地址
68
-	 * @return \poker\application\AbstractApplication
69
-	 */
70
-	public static function getInstance(string $rootPath = null): AbstractApplication
71
-	{
72
-		if (null === static::$instance) {
73
-			static::$instance = new static($rootPath ?: dirname($_SERVER['DOCUMENT_ROOT']));
74
-		}
64
+    /**
65
+     * 返回应用程序实例
66
+     *
67
+     * @param  string                                 $rootPath 应用程序根路径地址
68
+     * @return \poker\application\AbstractApplication
69
+     */
70
+    public static function getInstance(string $rootPath = null): AbstractApplication
71
+    {
72
+        if (null === static::$instance) {
73
+            static::$instance = new static($rootPath ?: dirname($_SERVER['DOCUMENT_ROOT']));
74
+        }
75 75
 
76
-		return static::$instance;
77
-	}
76
+        return static::$instance;
77
+    }
78 78
 
79
-	/**
80
-	 * 应用程序初始化
81
-	 */
82
-	protected function initialize(): void
83
-	{
84
-		$this->container->registerInstance([AbstractApplication::class, 'app'], $this);
85
-	}
79
+    /**
80
+     * 应用程序初始化
81
+     */
82
+    protected function initialize(): void
83
+    {
84
+        $this->container->registerInstance([AbstractApplication::class, 'app'], $this);
85
+    }
86 86
 
87
-	/**
88
-	 * 运行应用程序
89
-	 */
90
-	abstract public function run();
87
+    /**
88
+     * 运行应用程序
89
+     */
90
+    abstract public function run();
91 91
 }
Please login to merge, or discard this patch.
src/poker/container/traits/ContainerAwareTrait.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -19,53 +19,53 @@
 block discarded – undo
19 19
  */
20 20
 trait ContainerAwareTrait
21 21
 {
22
-	/**
23
-	 * 容器实例
24
-	 *
25
-	 * @var \poker\container\Container
26
-	 */
27
-	protected $container;
22
+    /**
23
+     * 容器实例
24
+     *
25
+     * @var \poker\container\Container
26
+     */
27
+    protected $container;
28 28
 
29
-	/**
30
-	 * 已解析对象的数组或对已解析对象的引用
31
-	 *
32
-	 * @var array
33
-	 */
34
-	protected $resolved = [];
29
+    /**
30
+     * 已解析对象的数组或对已解析对象的引用
31
+     *
32
+     * @var array
33
+     */
34
+    protected $resolved = [];
35 35
 
36
-	/**
37
-	 * 设置容器实例
38
-	 *
39
-	 * @param \poker\container\Container $container 容器实例
40
-	 */
41
-	public function setContainer(Container $container): void
42
-	{
43
-		$this->container = $container;
44
-	}
36
+    /**
37
+     * 设置容器实例
38
+     *
39
+     * @param \poker\container\Container $container 容器实例
40
+     */
41
+    public function setContainer(Container $container): void
42
+    {
43
+        $this->container = $container;
44
+    }
45 45
 
46
-	/**
47
-	 * 使用魔术方法从容器中解析项目
48
-	 *
49
-	 * @param  string            $key
50
-	 * @throws \RuntimeException
51
-	 * @return mixed
52
-	 */
53
-	public function __get(string $key)
54
-	{
55
-		if (isset($this->resolved[$key])) {
56
-			return $this->resolved[$key];
57
-		}
46
+    /**
47
+     * 使用魔术方法从容器中解析项目
48
+     *
49
+     * @param  string            $key
50
+     * @throws \RuntimeException
51
+     * @return mixed
52
+     */
53
+    public function __get(string $key)
54
+    {
55
+        if (isset($this->resolved[$key])) {
56
+            return $this->resolved[$key];
57
+        }
58 58
 
59
-		if ($this->container->has($key) === false) {
60
-			throw new RuntimeException(vsprintf('Unable to resolve [ %s ].', [$key]));
61
-		}
59
+        if ($this->container->has($key) === false) {
60
+            throw new RuntimeException(vsprintf('Unable to resolve [ %s ].', [$key]));
61
+        }
62 62
 
63
-		$resolved = $this->container->get($key);
63
+        $resolved = $this->container->get($key);
64 64
 
65
-		if ($this->container->isSingleton($key) === false) {
66
-			return $resolved;
67
-		}
65
+        if ($this->container->isSingleton($key) === false) {
66
+            return $resolved;
67
+        }
68 68
 
69
-		return $this->resolved[$key] = $resolved;
70
-	}
69
+        return $this->resolved[$key] = $resolved;
70
+    }
71 71
 }
Please login to merge, or discard this patch.
src/poker/container/ClassInspector.php 2 patches
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -16,37 +16,37 @@
 block discarded – undo
16 16
  */
17 17
 class ClassInspector
18 18
 {
19
-	/**
20
-	 * 返回一个类使用的所有trait的数组
21
-	 *
22
-	 * @param  string|object $class    类名或类实例
23
-	 * @param  bool          $autoload 是否自动加载
24
-	 * @return array
25
-	 */
26
-	public static function getTraits($class, bool $autoload = true): array
27
-	{
28
-		// 获取类及其父类使用的所有trial
29
-		$traits = [];
30
-		do {
31
-			$traits += class_uses($class, $autoload);
32
-		} while($class = get_parent_class($class));
19
+    /**
20
+     * 返回一个类使用的所有trait的数组
21
+     *
22
+     * @param  string|object $class    类名或类实例
23
+     * @param  bool          $autoload 是否自动加载
24
+     * @return array
25
+     */
26
+    public static function getTraits($class, bool $autoload = true): array
27
+    {
28
+        // 获取类及其父类使用的所有trial
29
+        $traits = [];
30
+        do {
31
+            $traits += class_uses($class, $autoload);
32
+        } while($class = get_parent_class($class));
33 33
 
34
-		// 寻找所有的trait
35
-		$search   = $traits;
36
-		$searched = [];
37
-		while (!empty($search)) {
38
-			$trait = array_pop($search);
34
+        // 寻找所有的trait
35
+        $search   = $traits;
36
+        $searched = [];
37
+        while (!empty($search)) {
38
+            $trait = array_pop($search);
39 39
 
40
-			if (isset($searched[$trait])) {
41
-				continue;
42
-			}
40
+            if (isset($searched[$trait])) {
41
+                continue;
42
+            }
43 43
 
44
-			$traits += $search += class_uses($trait, $autoload);
44
+            $traits += $search += class_uses($trait, $autoload);
45 45
 
46
-			$searched[$trait] = $trait;
47
-		}
46
+            $searched[$trait] = $trait;
47
+        }
48 48
 
49
-		// 返回该类使用的trait的完整列表
50
-		return $traits;
51
-	}
49
+        // 返回该类使用的trait的完整列表
50
+        return $traits;
51
+    }
52 52
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -29,7 +29,7 @@
 block discarded – undo
29 29
 		$traits = [];
30 30
 		do {
31 31
 			$traits += class_uses($class, $autoload);
32
-		} while($class = get_parent_class($class));
32
+		} while ($class = get_parent_class($class));
33 33
 
34 34
 		// 寻找所有的trait
35 35
 		$search   = $traits;
Please login to merge, or discard this patch.
src/poker/container/Container.php 2 patches
Indentation   +525 added lines, -525 removed lines patch added patch discarded remove patch
@@ -29,529 +29,529 @@
 block discarded – undo
29 29
  */
30 30
 class Container
31 31
 {
32
-	/**
33
-	 * 容器自身单例实例
34
-	 *
35
-	 * @var \poker\container\Container
36
-	 */
37
-	protected static $instance;
38
-
39
-	/**
40
-	 * 注册的类型提示
41
-	 *
42
-	 * @var array
43
-	 */
44
-	protected $hints = [];
45
-
46
-	/**
47
-	 * 别名
48
-	 *
49
-	 * @var array
50
-	 */
51
-	protected $aliases = [];
52
-
53
-	/**
54
-	 * 单例实例
55
-	 *
56
-	 * @var array
57
-	 */
58
-	protected $instances = [];
59
-
60
-	/**
61
-	 * 实例替换程序
62
-	 *
63
-	 * @var array
64
-	 */
65
-	protected $replacers = [];
66
-
67
-	/**
68
-	 * 上下文依赖关系
69
-	 *
70
-	 * @var array
71
-	 */
72
-	protected $dependencies = [];
73
-
74
-	/**
75
-	 * 返回容器自身单例实例
76
-	 *
77
-	 * @return \poker\container\Container
78
-	 */
79
-	public static function getInstance()
80
-	{
81
-		if (null === static::$instance) {
82
-			static::$instance = new static;
83
-		}
84
-
85
-		return static::$instance;
86
-	}
87
-
88
-	/**
89
-	 * 检查是否在容器中注册了类
90
-	 *
91
-	 * @param  string $class 类名
92
-	 * @return bool
93
-	 */
94
-	public function has(string $class): bool
95
-	{
96
-		$class = $this->resolveAlias($class);
97
-
98
-		return (isset($this->hints[$class]) || isset($this->instances[$class]));
99
-	}
100
-
101
-	/**
102
-	 * 如果一个类已注册为单例则返回TRUE,否则返回FALSE
103
-	 *
104
-	 * @param  string $class 类名
105
-	 * @return bool
106
-	 */
107
-	public function isSingleton(string $class): bool
108
-	{
109
-		$class = $this->resolveAlias($class);
110
-
111
-		return isset($this->instances[$class]) || (isset($this->hints[$class]) && $this->hints[$class]['singleton'] === true);
112
-	}
113
-
114
-	/**
115
-	 * 即使该类已注册为单例,也返回一个新的类实例
116
-	 *
117
-	 * @param  string $class      类名
118
-	 * @param  array  $parameters 构造函数参数
119
-	 * @return object
120
-	 */
121
-	public function getFresh(string $class, array $parameters = []): object
122
-	{
123
-		return $this->get($class, $parameters, false);
124
-	}
125
-
126
-	/**
127
-	 * 注册一个类型提示
128
-	 *
129
-	 * @param string|array    $hint      包含类型提示和别名的类型提示或数组
130
-	 * @param string|\Closure $class     类名或闭包
131
-	 * @param bool            $singleton 是否每次都应该返回相同的实例
132
-	 */
133
-	public function register($hint, $class, bool $singleton = false): void
134
-	{
135
-		$this->hints[$this->parseHint($hint)] = ['class' => $class, 'singleton' => $singleton];
136
-	}
137
-
138
-	/**
139
-	 * 注册一个类型提示并每次返回相同的实例
140
-	 *
141
-	 * @param string|array    $hint  包含类型提示和别名的类型提示或数组
142
-	 * @param string|\Closure $class 类名或闭包
143
-	 */
144
-	public function registerSingleton($hint, $class): void
145
-	{
146
-		$this->register($hint, $class, true);
147
-	}
148
-
149
-	/**
150
-	 * 注册一个单例实例
151
-	 *
152
-	 * @param string|array $hint     包含类型提示和别名的类型提示或数组
153
-	 * @param object       $instance 类实例
154
-	 */
155
-	public function registerInstance($hint, object $instance): void
156
-	{
157
-		$this->instances[$this->parseHint($hint)] = $instance;
158
-	}
159
-
160
-	/**
161
-	 * 替换一个已注册的类型提示
162
-	 *
163
-	 * @param  string                                         $hint      类型提示
164
-	 * @param  string|\Closure                                $class     类名或闭包
165
-	 * @param  bool                                           $singleton 是否替换一个单例
166
-	 * @throws \poker\container\exceptions\ContainerException
167
-	 */
168
-	public function replace(string $hint, $class, bool $singleton = false): void
169
-	{
170
-		$hint = $this->resolveAlias($hint);
171
-
172
-		if (!isset($this->hints[$hint])) {
173
-			throw new ContainerException(vsprintf('Unable to replace [ %s ] as it hasn\'t been registered.', [$hint]));
174
-		}
175
-
176
-		$this->hints[$hint]['class'] = $class;
177
-
178
-		if ($singleton) {
179
-			unset($this->instances[$hint]);
180
-		}
181
-
182
-		$this->replaceInstances($hint);
183
-	}
184
-
185
-	/**
186
-	 * 注册替换程序
187
-	 *
188
-	 * @param string      $hint      类型提示
189
-	 * @param callable    $replacer  实例替换程序
190
-	 * @param string|null $eventName 事件名称
191
-	 */
192
-	public function onReplace(string $hint, callable $replacer, ?string $eventName = null): void
193
-	{
194
-		$hint = $this->resolveAlias($hint);
195
-
196
-		$eventName === null ? ($this->replacers[$hint][] = $replacer) : ($this->replacers[$hint][$eventName] = $replacer);
197
-	}
198
-
199
-	/**
200
-	 * 替换一个已注册的单例类型提示
201
-	 *
202
-	 * @param string          $hint  类型提示
203
-	 * @param string|\Closure $class 类名或闭包
204
-	 */
205
-	public function replaceSingleton(string $hint, $class): void
206
-	{
207
-		$this->replace($hint, $class, true);
208
-	}
209
-
210
-	/**
211
-	 * 替换一个单例实例
212
-	 *
213
-	 * @param  string                                         $hint     类型提示
214
-	 * @param  object                                         $instance 类实例
215
-	 * @throws \poker\container\exceptions\ContainerException
216
-	 */
217
-	public function replaceInstance(string $hint, object $instance): void
218
-	{
219
-		$hint = $this->resolveAlias($hint);
220
-
221
-		if (!isset($this->instances[$hint])) {
222
-			throw new ContainerException(vsprintf('Unable to replace [ %s ] as it hasn\'t been registered.', [$hint]));
223
-		}
224
-
225
-		$this->instances[$hint] = $instance;
226
-
227
-		$this->replaceInstances($hint);
228
-	}
229
-
230
-	/**
231
-	 * 注册一个上下文依赖关系
232
-	 *
233
-	 * @param string $class          类
234
-	 * @param string $interface      接口
235
-	 * @param string $implementation 实现
236
-	 */
237
-	public function registerContextualDependency(string $class, string $interface, string $implementation): void
238
-	{
239
-		$this->dependencies[$class][$interface] = $implementation;
240
-	}
241
-
242
-	/**
243
-	 * 返回一个类实例
244
-	 *
245
-	 * @param  string $class         类名
246
-	 * @param  array  $parameters    构造函数参数
247
-	 * @param  bool   $reuseInstance 是否重用现有实例
248
-	 * @return object
249
-	 */
250
-	public function get(string $class, array $parameters = [], bool $reuseInstance = true): object
251
-	{
252
-		$class = $this->resolveAlias($class);
253
-
254
-		// 如果存在单例实例,直接返回它
255
-		if ($reuseInstance && isset($this->instances[$class])) {
256
-			return $this->instances[$class];
257
-		}
258
-
259
-		// 创建新实例
260
-		$instance = $this->factory($this->resolveHint($class), $parameters);
261
-
262
-		// 如果实例注册为单例,则存储该实例
263
-		if ($reuseInstance && isset($this->hints[$class]) && $this->hints[$class]['singleton']) {
264
-			$this->instances[$class] = $instance;
265
-		}
266
-
267
-		// 返回的实例
268
-		return $instance;
269
-	}
270
-
271
-	/**
272
-	 * 工厂创建一个类实例
273
-	 *
274
-	 * @param  string|\Closure $class      类名或闭包
275
-	 * @param  array           $parameters 构造函数参数
276
-	 * @return object
277
-	 */
278
-	public function factory($class, array $parameters = []): object
279
-	{
280
-		// 实例化类
281
-		if ($class instanceof Closure) {
282
-			$instance = $this->closureFactory($class, $parameters);
283
-		} else {
284
-			$instance = $this->reflectionFactory($class, $parameters);
285
-		}
286
-
287
-		// 如果类可以识别容器,则使用setter注入容器
288
-		if ($this->isContainerAware($instance)) {
289
-			$instance->setContainer($this);
290
-		}
291
-
292
-		// 返回的实例
293
-		return $instance;
294
-	}
295
-
296
-	/**
297
-	 * 执行可调用并注入其依赖项
298
-	 *
299
-	 * @param  callable $callable   可调用
300
-	 * @param  array    $parameters 参数
301
-	 * @return mixed
302
-	 */
303
-	public function call(callable $callable, array $parameters = [])
304
-	{
305
-		if (is_array($callable)) {
306
-			$reflection = new ReflectionMethod($callable[0], $callable[1]);
307
-		} else {
308
-			$reflection = new ReflectionFunction($callable);
309
-		}
310
-
311
-		return $callable(...$this->resolveParameters($reflection->getParameters(), $parameters));
312
-	}
313
-
314
-	/**
315
-	 * 使用工厂闭包创建一个类实例
316
-	 *
317
-	 * @param  \Closure $factory    类名或闭包
318
-	 * @param  array    $parameters 构造函数参数
319
-	 * @return object
320
-	 */
321
-	protected function closureFactory(Closure $factory, array $parameters): object
322
-	{
323
-		// 将容器作为第一个参数传递,然后传递所提供的参数
324
-		return $factory(...array_merge([$this], $parameters));
325
-	}
326
-
327
-	/**
328
-	 * 使用反射创建一个类实例
329
-	 *
330
-	 * @param  string                                                   $class      类名
331
-	 * @param  array                                                    $parameters 构造函数参数
332
-	 * @throws \poker\container\exceptions\UnableToInstantiateException
333
-	 * @return object
334
-	 */
335
-	protected function reflectionFactory(string $class, array $parameters): object
336
-	{
337
-		$class = new ReflectionClass($class);
338
-
339
-		// 检查是否可以实例化该类
340
-		if (!$class->isInstantiable()) {
341
-			throw new UnableToInstantiateException(vsprintf('Unable to create a [ %s ] instance.', [$class->getName()]));
342
-		}
343
-
344
-		// 获取类的构造函数
345
-		$constructor = $class->getConstructor();
346
-
347
-		// 如果没有构造函数,只返回一个新实例
348
-		if ($constructor === null) {
349
-			return $class->newInstance();
350
-		}
351
-
352
-		// 该类有一个构造函数,因此将使用解析的参数返回一个新实例
353
-		return $class->newInstanceArgs($this->resolveParameters($constructor->getParameters(), $parameters, $class));
354
-	}
355
-
356
-	/**
357
-	 * 检查类是否可识别容器
358
-	 *
359
-	 * @param  object $class 类实例
360
-	 * @return bool
361
-	 */
362
-	protected function isContainerAware(object $class): bool
363
-	{
364
-		$traits = ClassInspector::getTraits($class);
365
-
366
-		return isset($traits[ContainerAwareTrait::class]);
367
-	}
368
-
369
-	/**
370
-	 * 解析一个类型提示
371
-	 *
372
-	 * @param  string          $hint 类型提示
373
-	 * @return string|\Closure
374
-	 */
375
-	protected function resolveHint(string $hint)
376
-	{
377
-		return $this->hints[$hint]['class'] ?? $hint;
378
-	}
379
-
380
-	/**
381
-	 * 根据别名返回名称。如果不存在别名只返回收到的值
382
-	 *
383
-	 * @param  string $alias 别名
384
-	 * @return string
385
-	 */
386
-	protected function resolveAlias(string $alias): string
387
-	{
388
-		return $this->aliases[$alias] ?? $alias;
389
-	}
390
-
391
-	/**
392
-	 * 解析一个上下文依赖关系
393
-	 *
394
-	 * @param  string $class     类
395
-	 * @param  string $interface 接口
396
-	 * @return string
397
-	 */
398
-	protected function resolveContextualDependency(string $class, string $interface): string
399
-	{
400
-		return $this->dependencies[$class][$interface] ?? $interface;
401
-	}
402
-
403
-	/**
404
-	 * 解析提示参数
405
-	 *
406
-	 * @param  string|array $hint 包含类型提示和别名的类型提示或数组
407
-	 * @return string
408
-	 */
409
-	protected function parseHint($hint): string
410
-	{
411
-		if (is_array($hint)) {
412
-			[$hint, $alias] = $hint;
413
-
414
-			$this->aliases[$alias] = $hint;
415
-		}
416
-
417
-		return $hint;
418
-	}
419
-
420
-	/**
421
-	 * 解析一个参数
422
-	 *
423
-	 * @param  \ReflectionParameter                                          $parameter 反射参数实例
424
-	 * @param  \ReflectionClass|null                                         $class     反射类实例
425
-	 * @throws \poker\container\exceptions\UnableToInstantiateException
426
-	 * @throws \poker\container\exceptions\UnableToResolveParameterException
427
-	 * @return mixed
428
-	 */
429
-	protected function resolveParameter(ReflectionParameter $parameter, ?ReflectionClass $class = null)
430
-	{
431
-		// 如果参数是类实例,将尝试使用容器解析它
432
-		if (($parameterClass = $parameter->getClass()) !== null) {
433
-			$parameterClassName = $parameterClass->getName();
434
-
435
-			if ($class !== null) {
436
-				$parameterClassName = $this->resolveContextualDependency($class->getName(), $parameterClassName);
437
-			}
438
-
439
-			try {
440
-				return $this->get($parameterClassName);
441
-			} catch(UnableToInstantiateException | UnableToResolveParameterException $e) {
442
-				if ($parameter->allowsNull()) {
443
-					return null;
444
-				}
445
-
446
-				throw $e;
447
-			}
448
-		}
449
-
450
-		// 如果参数有一个默认值,将使直接使用它
451
-		if ($parameter->isDefaultValueAvailable()) {
452
-			return $parameter->getDefaultValue();
453
-		}
454
-
455
-		// 该参数可以为空,因此只返回null
456
-		if ($parameter->hasType() && $parameter->allowsNull()) {
457
-			return null;
458
-		}
459
-
460
-		// 如果上述条件都不成立,则抛出异常消息
461
-		throw new UnableToResolveParameterException(vsprintf('Unable to resolve the [ $%s ] parameter of [ %s ].', [$parameter->getName(), $this->getDeclaringFunction($parameter)]));
462
-	}
463
-
464
-	/**
465
-	 * 解析多个参数
466
-	 *
467
-	 * @param  array                 $reflectionParameters 反射参数
468
-	 * @param  array                 $providedParameters   提供的参数
469
-	 * @param  \ReflectionClass|null $class                反射类实例
470
-	 * @return array
471
-	 */
472
-	protected function resolveParameters(array $reflectionParameters, array $providedParameters, ?ReflectionClass $class = null): array
473
-	{
474
-		if (empty($reflectionParameters)) {
475
-			return array_values($providedParameters);
476
-		}
477
-
478
-		// 将提供的参数与使用反射得到的参数合并
479
-		$parameters = $this->mergeParameters($reflectionParameters, $providedParameters);
480
-
481
-		// 循环遍历参数并处理需要解析的参数
482
-		foreach ($parameters as $key => $parameter) {
483
-			if ($parameter instanceof ReflectionParameter) {
484
-				$parameters[$key] = $this->resolveParameter($parameter, $class);
485
-			}
486
-		}
487
-
488
-		// 返回解析的参数
489
-		return array_values($parameters);
490
-	}
491
-
492
-	/**
493
-	 * 将提供的参数与反射参数合并
494
-	 *
495
-	 * @param  array $reflectionParameters 反射参数
496
-	 * @param  array $providedParameters   提供的参数
497
-	 * @return array
498
-	 */
499
-	protected function mergeParameters(array $reflectionParameters, array $providedParameters): array
500
-	{
501
-		// 使反射参数数组关联
502
-		$associativeReflectionParameters = [];
503
-		foreach ($reflectionParameters as $value) {
504
-			$associativeReflectionParameters[$value->getName()] = $value;
505
-		}
506
-
507
-		// 使提供的参数数组关联
508
-		$associativeProvidedParameters = [];
509
-		foreach ($providedParameters as $key => $value) {
510
-			if (is_int($key)) {
511
-				$associativeProvidedParameters[$reflectionParameters[$key]->getName()] = $value;
512
-			} else {
513
-				$associativeProvidedParameters[$key] = $value;
514
-			}
515
-		}
516
-
517
-		// 返回合并后的参数
518
-		return array_replace($associativeReflectionParameters, $associativeProvidedParameters);
519
-	}
520
-
521
-	/**
522
-	 * 返回声明函数的名称
523
-	 *
524
-	 * @param  \ReflectionParameter $parameter 反射参数实例
525
-	 * @return string
526
-	 */
527
-	protected function getDeclaringFunction(ReflectionParameter $parameter): string
528
-	{
529
-		$declaringFunction = $parameter->getDeclaringFunction();
530
-
531
-		if ($declaringFunction->isClosure()) {
532
-			return 'Closure';
533
-		}
534
-
535
-		if (($class = $parameter->getDeclaringClass()) === null) {
536
-			return $declaringFunction->getName();
537
-		}
538
-
539
-		return $class->getName() . '::' . $declaringFunction->getName();
540
-	}
541
-
542
-	/**
543
-	 * 替换以前解析的实例
544
-	 *
545
-	 * @param string $hint 类型提示
546
-	 */
547
-	protected function replaceInstances(string $hint): void
548
-	{
549
-		if (isset($this->replacers[$hint])) {
550
-			$instance = $this->get($hint);
551
-
552
-			foreach ($this->replacers[$hint] as $replacer) {
553
-				$replacer($instance);
554
-			}
555
-		}
556
-	}
32
+    /**
33
+     * 容器自身单例实例
34
+     *
35
+     * @var \poker\container\Container
36
+     */
37
+    protected static $instance;
38
+
39
+    /**
40
+     * 注册的类型提示
41
+     *
42
+     * @var array
43
+     */
44
+    protected $hints = [];
45
+
46
+    /**
47
+     * 别名
48
+     *
49
+     * @var array
50
+     */
51
+    protected $aliases = [];
52
+
53
+    /**
54
+     * 单例实例
55
+     *
56
+     * @var array
57
+     */
58
+    protected $instances = [];
59
+
60
+    /**
61
+     * 实例替换程序
62
+     *
63
+     * @var array
64
+     */
65
+    protected $replacers = [];
66
+
67
+    /**
68
+     * 上下文依赖关系
69
+     *
70
+     * @var array
71
+     */
72
+    protected $dependencies = [];
73
+
74
+    /**
75
+     * 返回容器自身单例实例
76
+     *
77
+     * @return \poker\container\Container
78
+     */
79
+    public static function getInstance()
80
+    {
81
+        if (null === static::$instance) {
82
+            static::$instance = new static;
83
+        }
84
+
85
+        return static::$instance;
86
+    }
87
+
88
+    /**
89
+     * 检查是否在容器中注册了类
90
+     *
91
+     * @param  string $class 类名
92
+     * @return bool
93
+     */
94
+    public function has(string $class): bool
95
+    {
96
+        $class = $this->resolveAlias($class);
97
+
98
+        return (isset($this->hints[$class]) || isset($this->instances[$class]));
99
+    }
100
+
101
+    /**
102
+     * 如果一个类已注册为单例则返回TRUE,否则返回FALSE
103
+     *
104
+     * @param  string $class 类名
105
+     * @return bool
106
+     */
107
+    public function isSingleton(string $class): bool
108
+    {
109
+        $class = $this->resolveAlias($class);
110
+
111
+        return isset($this->instances[$class]) || (isset($this->hints[$class]) && $this->hints[$class]['singleton'] === true);
112
+    }
113
+
114
+    /**
115
+     * 即使该类已注册为单例,也返回一个新的类实例
116
+     *
117
+     * @param  string $class      类名
118
+     * @param  array  $parameters 构造函数参数
119
+     * @return object
120
+     */
121
+    public function getFresh(string $class, array $parameters = []): object
122
+    {
123
+        return $this->get($class, $parameters, false);
124
+    }
125
+
126
+    /**
127
+     * 注册一个类型提示
128
+     *
129
+     * @param string|array    $hint      包含类型提示和别名的类型提示或数组
130
+     * @param string|\Closure $class     类名或闭包
131
+     * @param bool            $singleton 是否每次都应该返回相同的实例
132
+     */
133
+    public function register($hint, $class, bool $singleton = false): void
134
+    {
135
+        $this->hints[$this->parseHint($hint)] = ['class' => $class, 'singleton' => $singleton];
136
+    }
137
+
138
+    /**
139
+     * 注册一个类型提示并每次返回相同的实例
140
+     *
141
+     * @param string|array    $hint  包含类型提示和别名的类型提示或数组
142
+     * @param string|\Closure $class 类名或闭包
143
+     */
144
+    public function registerSingleton($hint, $class): void
145
+    {
146
+        $this->register($hint, $class, true);
147
+    }
148
+
149
+    /**
150
+     * 注册一个单例实例
151
+     *
152
+     * @param string|array $hint     包含类型提示和别名的类型提示或数组
153
+     * @param object       $instance 类实例
154
+     */
155
+    public function registerInstance($hint, object $instance): void
156
+    {
157
+        $this->instances[$this->parseHint($hint)] = $instance;
158
+    }
159
+
160
+    /**
161
+     * 替换一个已注册的类型提示
162
+     *
163
+     * @param  string                                         $hint      类型提示
164
+     * @param  string|\Closure                                $class     类名或闭包
165
+     * @param  bool                                           $singleton 是否替换一个单例
166
+     * @throws \poker\container\exceptions\ContainerException
167
+     */
168
+    public function replace(string $hint, $class, bool $singleton = false): void
169
+    {
170
+        $hint = $this->resolveAlias($hint);
171
+
172
+        if (!isset($this->hints[$hint])) {
173
+            throw new ContainerException(vsprintf('Unable to replace [ %s ] as it hasn\'t been registered.', [$hint]));
174
+        }
175
+
176
+        $this->hints[$hint]['class'] = $class;
177
+
178
+        if ($singleton) {
179
+            unset($this->instances[$hint]);
180
+        }
181
+
182
+        $this->replaceInstances($hint);
183
+    }
184
+
185
+    /**
186
+     * 注册替换程序
187
+     *
188
+     * @param string      $hint      类型提示
189
+     * @param callable    $replacer  实例替换程序
190
+     * @param string|null $eventName 事件名称
191
+     */
192
+    public function onReplace(string $hint, callable $replacer, ?string $eventName = null): void
193
+    {
194
+        $hint = $this->resolveAlias($hint);
195
+
196
+        $eventName === null ? ($this->replacers[$hint][] = $replacer) : ($this->replacers[$hint][$eventName] = $replacer);
197
+    }
198
+
199
+    /**
200
+     * 替换一个已注册的单例类型提示
201
+     *
202
+     * @param string          $hint  类型提示
203
+     * @param string|\Closure $class 类名或闭包
204
+     */
205
+    public function replaceSingleton(string $hint, $class): void
206
+    {
207
+        $this->replace($hint, $class, true);
208
+    }
209
+
210
+    /**
211
+     * 替换一个单例实例
212
+     *
213
+     * @param  string                                         $hint     类型提示
214
+     * @param  object                                         $instance 类实例
215
+     * @throws \poker\container\exceptions\ContainerException
216
+     */
217
+    public function replaceInstance(string $hint, object $instance): void
218
+    {
219
+        $hint = $this->resolveAlias($hint);
220
+
221
+        if (!isset($this->instances[$hint])) {
222
+            throw new ContainerException(vsprintf('Unable to replace [ %s ] as it hasn\'t been registered.', [$hint]));
223
+        }
224
+
225
+        $this->instances[$hint] = $instance;
226
+
227
+        $this->replaceInstances($hint);
228
+    }
229
+
230
+    /**
231
+     * 注册一个上下文依赖关系
232
+     *
233
+     * @param string $class          类
234
+     * @param string $interface      接口
235
+     * @param string $implementation 实现
236
+     */
237
+    public function registerContextualDependency(string $class, string $interface, string $implementation): void
238
+    {
239
+        $this->dependencies[$class][$interface] = $implementation;
240
+    }
241
+
242
+    /**
243
+     * 返回一个类实例
244
+     *
245
+     * @param  string $class         类名
246
+     * @param  array  $parameters    构造函数参数
247
+     * @param  bool   $reuseInstance 是否重用现有实例
248
+     * @return object
249
+     */
250
+    public function get(string $class, array $parameters = [], bool $reuseInstance = true): object
251
+    {
252
+        $class = $this->resolveAlias($class);
253
+
254
+        // 如果存在单例实例,直接返回它
255
+        if ($reuseInstance && isset($this->instances[$class])) {
256
+            return $this->instances[$class];
257
+        }
258
+
259
+        // 创建新实例
260
+        $instance = $this->factory($this->resolveHint($class), $parameters);
261
+
262
+        // 如果实例注册为单例,则存储该实例
263
+        if ($reuseInstance && isset($this->hints[$class]) && $this->hints[$class]['singleton']) {
264
+            $this->instances[$class] = $instance;
265
+        }
266
+
267
+        // 返回的实例
268
+        return $instance;
269
+    }
270
+
271
+    /**
272
+     * 工厂创建一个类实例
273
+     *
274
+     * @param  string|\Closure $class      类名或闭包
275
+     * @param  array           $parameters 构造函数参数
276
+     * @return object
277
+     */
278
+    public function factory($class, array $parameters = []): object
279
+    {
280
+        // 实例化类
281
+        if ($class instanceof Closure) {
282
+            $instance = $this->closureFactory($class, $parameters);
283
+        } else {
284
+            $instance = $this->reflectionFactory($class, $parameters);
285
+        }
286
+
287
+        // 如果类可以识别容器,则使用setter注入容器
288
+        if ($this->isContainerAware($instance)) {
289
+            $instance->setContainer($this);
290
+        }
291
+
292
+        // 返回的实例
293
+        return $instance;
294
+    }
295
+
296
+    /**
297
+     * 执行可调用并注入其依赖项
298
+     *
299
+     * @param  callable $callable   可调用
300
+     * @param  array    $parameters 参数
301
+     * @return mixed
302
+     */
303
+    public function call(callable $callable, array $parameters = [])
304
+    {
305
+        if (is_array($callable)) {
306
+            $reflection = new ReflectionMethod($callable[0], $callable[1]);
307
+        } else {
308
+            $reflection = new ReflectionFunction($callable);
309
+        }
310
+
311
+        return $callable(...$this->resolveParameters($reflection->getParameters(), $parameters));
312
+    }
313
+
314
+    /**
315
+     * 使用工厂闭包创建一个类实例
316
+     *
317
+     * @param  \Closure $factory    类名或闭包
318
+     * @param  array    $parameters 构造函数参数
319
+     * @return object
320
+     */
321
+    protected function closureFactory(Closure $factory, array $parameters): object
322
+    {
323
+        // 将容器作为第一个参数传递,然后传递所提供的参数
324
+        return $factory(...array_merge([$this], $parameters));
325
+    }
326
+
327
+    /**
328
+     * 使用反射创建一个类实例
329
+     *
330
+     * @param  string                                                   $class      类名
331
+     * @param  array                                                    $parameters 构造函数参数
332
+     * @throws \poker\container\exceptions\UnableToInstantiateException
333
+     * @return object
334
+     */
335
+    protected function reflectionFactory(string $class, array $parameters): object
336
+    {
337
+        $class = new ReflectionClass($class);
338
+
339
+        // 检查是否可以实例化该类
340
+        if (!$class->isInstantiable()) {
341
+            throw new UnableToInstantiateException(vsprintf('Unable to create a [ %s ] instance.', [$class->getName()]));
342
+        }
343
+
344
+        // 获取类的构造函数
345
+        $constructor = $class->getConstructor();
346
+
347
+        // 如果没有构造函数,只返回一个新实例
348
+        if ($constructor === null) {
349
+            return $class->newInstance();
350
+        }
351
+
352
+        // 该类有一个构造函数,因此将使用解析的参数返回一个新实例
353
+        return $class->newInstanceArgs($this->resolveParameters($constructor->getParameters(), $parameters, $class));
354
+    }
355
+
356
+    /**
357
+     * 检查类是否可识别容器
358
+     *
359
+     * @param  object $class 类实例
360
+     * @return bool
361
+     */
362
+    protected function isContainerAware(object $class): bool
363
+    {
364
+        $traits = ClassInspector::getTraits($class);
365
+
366
+        return isset($traits[ContainerAwareTrait::class]);
367
+    }
368
+
369
+    /**
370
+     * 解析一个类型提示
371
+     *
372
+     * @param  string          $hint 类型提示
373
+     * @return string|\Closure
374
+     */
375
+    protected function resolveHint(string $hint)
376
+    {
377
+        return $this->hints[$hint]['class'] ?? $hint;
378
+    }
379
+
380
+    /**
381
+     * 根据别名返回名称。如果不存在别名只返回收到的值
382
+     *
383
+     * @param  string $alias 别名
384
+     * @return string
385
+     */
386
+    protected function resolveAlias(string $alias): string
387
+    {
388
+        return $this->aliases[$alias] ?? $alias;
389
+    }
390
+
391
+    /**
392
+     * 解析一个上下文依赖关系
393
+     *
394
+     * @param  string $class     类
395
+     * @param  string $interface 接口
396
+     * @return string
397
+     */
398
+    protected function resolveContextualDependency(string $class, string $interface): string
399
+    {
400
+        return $this->dependencies[$class][$interface] ?? $interface;
401
+    }
402
+
403
+    /**
404
+     * 解析提示参数
405
+     *
406
+     * @param  string|array $hint 包含类型提示和别名的类型提示或数组
407
+     * @return string
408
+     */
409
+    protected function parseHint($hint): string
410
+    {
411
+        if (is_array($hint)) {
412
+            [$hint, $alias] = $hint;
413
+
414
+            $this->aliases[$alias] = $hint;
415
+        }
416
+
417
+        return $hint;
418
+    }
419
+
420
+    /**
421
+     * 解析一个参数
422
+     *
423
+     * @param  \ReflectionParameter                                          $parameter 反射参数实例
424
+     * @param  \ReflectionClass|null                                         $class     反射类实例
425
+     * @throws \poker\container\exceptions\UnableToInstantiateException
426
+     * @throws \poker\container\exceptions\UnableToResolveParameterException
427
+     * @return mixed
428
+     */
429
+    protected function resolveParameter(ReflectionParameter $parameter, ?ReflectionClass $class = null)
430
+    {
431
+        // 如果参数是类实例,将尝试使用容器解析它
432
+        if (($parameterClass = $parameter->getClass()) !== null) {
433
+            $parameterClassName = $parameterClass->getName();
434
+
435
+            if ($class !== null) {
436
+                $parameterClassName = $this->resolveContextualDependency($class->getName(), $parameterClassName);
437
+            }
438
+
439
+            try {
440
+                return $this->get($parameterClassName);
441
+            } catch(UnableToInstantiateException | UnableToResolveParameterException $e) {
442
+                if ($parameter->allowsNull()) {
443
+                    return null;
444
+                }
445
+
446
+                throw $e;
447
+            }
448
+        }
449
+
450
+        // 如果参数有一个默认值,将使直接使用它
451
+        if ($parameter->isDefaultValueAvailable()) {
452
+            return $parameter->getDefaultValue();
453
+        }
454
+
455
+        // 该参数可以为空,因此只返回null
456
+        if ($parameter->hasType() && $parameter->allowsNull()) {
457
+            return null;
458
+        }
459
+
460
+        // 如果上述条件都不成立,则抛出异常消息
461
+        throw new UnableToResolveParameterException(vsprintf('Unable to resolve the [ $%s ] parameter of [ %s ].', [$parameter->getName(), $this->getDeclaringFunction($parameter)]));
462
+    }
463
+
464
+    /**
465
+     * 解析多个参数
466
+     *
467
+     * @param  array                 $reflectionParameters 反射参数
468
+     * @param  array                 $providedParameters   提供的参数
469
+     * @param  \ReflectionClass|null $class                反射类实例
470
+     * @return array
471
+     */
472
+    protected function resolveParameters(array $reflectionParameters, array $providedParameters, ?ReflectionClass $class = null): array
473
+    {
474
+        if (empty($reflectionParameters)) {
475
+            return array_values($providedParameters);
476
+        }
477
+
478
+        // 将提供的参数与使用反射得到的参数合并
479
+        $parameters = $this->mergeParameters($reflectionParameters, $providedParameters);
480
+
481
+        // 循环遍历参数并处理需要解析的参数
482
+        foreach ($parameters as $key => $parameter) {
483
+            if ($parameter instanceof ReflectionParameter) {
484
+                $parameters[$key] = $this->resolveParameter($parameter, $class);
485
+            }
486
+        }
487
+
488
+        // 返回解析的参数
489
+        return array_values($parameters);
490
+    }
491
+
492
+    /**
493
+     * 将提供的参数与反射参数合并
494
+     *
495
+     * @param  array $reflectionParameters 反射参数
496
+     * @param  array $providedParameters   提供的参数
497
+     * @return array
498
+     */
499
+    protected function mergeParameters(array $reflectionParameters, array $providedParameters): array
500
+    {
501
+        // 使反射参数数组关联
502
+        $associativeReflectionParameters = [];
503
+        foreach ($reflectionParameters as $value) {
504
+            $associativeReflectionParameters[$value->getName()] = $value;
505
+        }
506
+
507
+        // 使提供的参数数组关联
508
+        $associativeProvidedParameters = [];
509
+        foreach ($providedParameters as $key => $value) {
510
+            if (is_int($key)) {
511
+                $associativeProvidedParameters[$reflectionParameters[$key]->getName()] = $value;
512
+            } else {
513
+                $associativeProvidedParameters[$key] = $value;
514
+            }
515
+        }
516
+
517
+        // 返回合并后的参数
518
+        return array_replace($associativeReflectionParameters, $associativeProvidedParameters);
519
+    }
520
+
521
+    /**
522
+     * 返回声明函数的名称
523
+     *
524
+     * @param  \ReflectionParameter $parameter 反射参数实例
525
+     * @return string
526
+     */
527
+    protected function getDeclaringFunction(ReflectionParameter $parameter): string
528
+    {
529
+        $declaringFunction = $parameter->getDeclaringFunction();
530
+
531
+        if ($declaringFunction->isClosure()) {
532
+            return 'Closure';
533
+        }
534
+
535
+        if (($class = $parameter->getDeclaringClass()) === null) {
536
+            return $declaringFunction->getName();
537
+        }
538
+
539
+        return $class->getName() . '::' . $declaringFunction->getName();
540
+    }
541
+
542
+    /**
543
+     * 替换以前解析的实例
544
+     *
545
+     * @param string $hint 类型提示
546
+     */
547
+    protected function replaceInstances(string $hint): void
548
+    {
549
+        if (isset($this->replacers[$hint])) {
550
+            $instance = $this->get($hint);
551
+
552
+            foreach ($this->replacers[$hint] as $replacer) {
553
+                $replacer($instance);
554
+            }
555
+        }
556
+    }
557 557
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
 
439 439
 			try {
440 440
 				return $this->get($parameterClassName);
441
-			} catch(UnableToInstantiateException | UnableToResolveParameterException $e) {
441
+			} catch (UnableToInstantiateException | UnableToResolveParameterException $e) {
442 442
 				if ($parameter->allowsNull()) {
443 443
 					return null;
444 444
 				}
@@ -536,7 +536,7 @@  discard block
 block discarded – undo
536 536
 			return $declaringFunction->getName();
537 537
 		}
538 538
 
539
-		return $class->getName() . '::' . $declaringFunction->getName();
539
+		return $class->getName().'::'.$declaringFunction->getName();
540 540
 	}
541 541
 
542 542
 	/**
Please login to merge, or discard this patch.