|
1
|
|
|
<?php |
|
2
|
|
|
// +---------------------------------------------------------------------- |
|
3
|
|
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ] |
|
4
|
|
|
// +---------------------------------------------------------------------- |
|
5
|
|
|
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. |
|
6
|
|
|
// +---------------------------------------------------------------------- |
|
7
|
|
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) |
|
8
|
|
|
// +---------------------------------------------------------------------- |
|
9
|
|
|
// | Author: liu21st <[email protected]> |
|
10
|
|
|
// +---------------------------------------------------------------------- |
|
11
|
|
|
declare (strict_types = 1); |
|
12
|
|
|
|
|
13
|
|
|
namespace think; |
|
14
|
|
|
|
|
15
|
|
|
use ReflectionClass; |
|
16
|
|
|
use ReflectionMethod; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* 事件管理类 |
|
20
|
|
|
* @package think |
|
21
|
|
|
*/ |
|
22
|
|
|
class Event |
|
23
|
|
|
{ |
|
24
|
|
|
/** |
|
25
|
|
|
* 监听者 |
|
26
|
|
|
* @var array |
|
27
|
|
|
*/ |
|
28
|
|
|
protected $listener = []; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* 事件别名 |
|
32
|
|
|
* @var array |
|
33
|
|
|
*/ |
|
34
|
|
|
protected $bind = [ |
|
35
|
|
|
'AppInit' => event\AppInit::class, |
|
36
|
|
|
'HttpRun' => event\HttpRun::class, |
|
37
|
|
|
'HttpEnd' => event\HttpEnd::class, |
|
38
|
|
|
'RouteLoaded' => event\RouteLoaded::class, |
|
39
|
|
|
'LogWrite' => event\LogWrite::class, |
|
40
|
|
|
]; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* 应用对象 |
|
44
|
|
|
* @var App |
|
45
|
|
|
*/ |
|
46
|
|
|
protected $app; |
|
47
|
|
|
|
|
48
|
27 |
|
public function __construct(App $app) |
|
49
|
|
|
{ |
|
50
|
27 |
|
$this->app = $app; |
|
51
|
27 |
|
} |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* 批量注册事件监听 |
|
55
|
|
|
* @access public |
|
56
|
|
|
* @param array $events 事件定义 |
|
57
|
|
|
* @return $this |
|
58
|
|
|
*/ |
|
59
|
3 |
|
public function listenEvents(array $events) |
|
60
|
|
|
{ |
|
61
|
3 |
|
foreach ($events as $event => $listeners) { |
|
62
|
3 |
|
if (isset($this->bind[$event])) { |
|
63
|
|
|
$event = $this->bind[$event]; |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
3 |
|
$this->listener[$event] = array_merge($this->listener[$event] ?? [], $listeners); |
|
67
|
|
|
} |
|
68
|
|
|
|
|
69
|
3 |
|
return $this; |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* 注册事件监听 |
|
74
|
|
|
* @access public |
|
75
|
|
|
* @param string $event 事件名称 |
|
76
|
|
|
* @param mixed $listener 监听操作(或者类名) |
|
77
|
|
|
* @param bool $first 是否优先执行 |
|
78
|
|
|
* @return $this |
|
79
|
|
|
*/ |
|
80
|
12 |
|
public function listen(string $event, $listener, bool $first = false) |
|
81
|
|
|
{ |
|
82
|
12 |
|
if (isset($this->bind[$event])) { |
|
83
|
6 |
|
$event = $this->bind[$event]; |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
12 |
View Code Duplication |
if ($first && isset($this->listener[$event])) { |
|
|
|
|
|
|
87
|
|
|
array_unshift($this->listener[$event], $listener); |
|
88
|
|
|
} else { |
|
89
|
12 |
|
$this->listener[$event][] = $listener; |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
12 |
|
return $this; |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
/** |
|
96
|
|
|
* 是否存在事件监听 |
|
97
|
|
|
* @access public |
|
98
|
|
|
* @param string $event 事件名称 |
|
99
|
|
|
* @return bool |
|
100
|
|
|
*/ |
|
101
|
6 |
View Code Duplication |
public function hasListener(string $event): bool |
|
|
|
|
|
|
102
|
|
|
{ |
|
103
|
6 |
|
if (isset($this->bind[$event])) { |
|
104
|
3 |
|
$event = $this->bind[$event]; |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
6 |
|
return isset($this->listener[$event]); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
/** |
|
111
|
|
|
* 移除事件监听 |
|
112
|
|
|
* @access public |
|
113
|
|
|
* @param string $event 事件名称 |
|
114
|
|
|
* @return void |
|
115
|
|
|
*/ |
|
116
|
3 |
View Code Duplication |
public function remove(string $event): void |
|
|
|
|
|
|
117
|
|
|
{ |
|
118
|
3 |
|
if (isset($this->bind[$event])) { |
|
119
|
3 |
|
$event = $this->bind[$event]; |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
3 |
|
unset($this->listener[$event]); |
|
123
|
3 |
|
} |
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* 指定事件别名标识 便于调用 |
|
127
|
|
|
* @access public |
|
128
|
|
|
* @param array $events 事件别名 |
|
129
|
|
|
* @return $this |
|
130
|
|
|
*/ |
|
131
|
3 |
|
public function bind(array $events) |
|
132
|
|
|
{ |
|
133
|
3 |
|
$this->bind = array_merge($this->bind, $events); |
|
134
|
|
|
|
|
135
|
3 |
|
return $this; |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* 注册事件订阅者 |
|
140
|
|
|
* @access public |
|
141
|
|
|
* @param mixed $subscriber 订阅者 |
|
142
|
|
|
* @return $this |
|
143
|
|
|
*/ |
|
144
|
3 |
|
public function subscribe($subscriber) |
|
145
|
|
|
{ |
|
146
|
3 |
|
$subscribers = (array) $subscriber; |
|
147
|
|
|
|
|
148
|
3 |
|
foreach ($subscribers as $subscriber) { |
|
149
|
3 |
|
if (is_string($subscriber)) { |
|
150
|
3 |
|
$subscriber = $this->app->make($subscriber); |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
3 |
|
if (method_exists($subscriber, 'subscribe')) { |
|
154
|
|
|
// 手动订阅 |
|
155
|
3 |
|
$subscriber->subscribe($this); |
|
156
|
|
|
} else { |
|
157
|
|
|
// 智能订阅 |
|
158
|
1 |
|
$this->observe($subscriber); |
|
159
|
|
|
} |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
3 |
|
return $this; |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* 自动注册事件观察者 |
|
167
|
|
|
* @access public |
|
168
|
|
|
* @param string|object $observer 观察者 |
|
169
|
|
|
* @param null|string $prefix 事件名前缀 |
|
170
|
|
|
* @return $this |
|
171
|
|
|
*/ |
|
172
|
3 |
|
public function observe($observer, string $prefix = '') |
|
173
|
|
|
{ |
|
174
|
3 |
|
if (is_string($observer)) { |
|
175
|
3 |
|
$observer = $this->app->make($observer); |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
3 |
|
$reflect = new ReflectionClass($observer); |
|
179
|
3 |
|
$methods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC); |
|
180
|
|
|
|
|
181
|
3 |
|
if (empty($prefix) && $reflect->hasProperty('eventPrefix')) { |
|
182
|
|
|
$reflectProperty = $reflect->getProperty('eventPrefix'); |
|
183
|
|
|
$reflectProperty->setAccessible(true); |
|
184
|
|
|
$prefix = $reflectProperty->getValue($observer); |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
3 |
|
foreach ($methods as $method) { |
|
188
|
3 |
|
$name = $method->getName(); |
|
|
|
|
|
|
189
|
3 |
|
if (0 === strpos($name, 'on')) { |
|
190
|
3 |
|
$this->listen($prefix . substr($name, 2), [$observer, $name]); |
|
191
|
|
|
} |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
3 |
|
return $this; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
/** |
|
198
|
|
|
* 触发事件 |
|
199
|
|
|
* @access public |
|
200
|
|
|
* @param string|object $event 事件名称 |
|
201
|
|
|
* @param mixed $params 传入参数 |
|
202
|
|
|
* @param bool $once 只获取一个有效返回值 |
|
203
|
|
|
* @return mixed |
|
204
|
|
|
*/ |
|
205
|
24 |
|
public function trigger($event, $params = null, bool $once = false) |
|
206
|
|
|
{ |
|
207
|
24 |
|
if (is_object($event)) { |
|
208
|
6 |
|
$params = $event; |
|
209
|
6 |
|
$event = get_class($event); |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
24 |
|
if (isset($this->bind[$event])) { |
|
213
|
3 |
|
$event = $this->bind[$event]; |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
24 |
|
$result = []; |
|
217
|
24 |
|
$listeners = $this->listener[$event] ?? []; |
|
218
|
24 |
|
$listeners = array_unique($listeners, SORT_REGULAR); |
|
219
|
|
|
|
|
220
|
24 |
|
foreach ($listeners as $key => $listener) { |
|
221
|
12 |
|
$result[$key] = $this->dispatch($listener, $params); |
|
222
|
|
|
|
|
223
|
12 |
|
if (false === $result[$key] || (!is_null($result[$key]) && $once)) { |
|
224
|
10 |
|
break; |
|
225
|
|
|
} |
|
226
|
|
|
} |
|
227
|
|
|
|
|
228
|
24 |
|
return $once ? end($result) : $result; |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
/** |
|
232
|
|
|
* 触发事件(只获取一个有效返回值) |
|
233
|
|
|
* @param $event |
|
234
|
|
|
* @param null $params |
|
235
|
|
|
* @return mixed |
|
236
|
|
|
*/ |
|
237
|
3 |
|
public function until($event, $params = null) |
|
238
|
|
|
{ |
|
239
|
3 |
|
return $this->trigger($event, $params, true); |
|
240
|
|
|
} |
|
241
|
|
|
|
|
242
|
|
|
/** |
|
243
|
|
|
* 执行事件调度 |
|
244
|
|
|
* @access protected |
|
245
|
|
|
* @param mixed $event 事件方法 |
|
246
|
|
|
* @param mixed $params 参数 |
|
247
|
|
|
* @return mixed |
|
248
|
|
|
*/ |
|
249
|
12 |
|
protected function dispatch($event, $params = null) |
|
250
|
|
|
{ |
|
251
|
12 |
|
if (!is_string($event)) { |
|
252
|
9 |
|
$call = $event; |
|
253
|
3 |
|
} elseif (strpos($event, '::')) { |
|
254
|
|
|
$call = $event; |
|
255
|
|
|
} else { |
|
256
|
3 |
|
$obj = $this->app->make($event); |
|
257
|
3 |
|
$call = [$obj, 'handle']; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
12 |
|
return $this->app->invoke($call, [$params]); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
} |
|
264
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.