1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Dazzle\Event; |
4
|
|
|
|
5
|
|
|
trait BaseEventEmitterTrait |
6
|
|
|
{ |
7
|
|
|
/** |
8
|
|
|
* @var int |
9
|
|
|
*/ |
10
|
|
|
protected $emitterBlocked = EventEmitter::EVENTS_FORWARD; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* @var int[] |
14
|
|
|
*/ |
15
|
|
|
protected $eventPointers = []; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @var EventListener[][] |
19
|
|
|
*/ |
20
|
|
|
protected $eventListeners = []; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var EventEmitterInterface[] |
24
|
|
|
*/ |
25
|
|
|
protected $forwardListeners = []; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* |
29
|
|
|
*/ |
30
|
39 |
|
public function __construct() |
31
|
39 |
|
{} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* |
35
|
|
|
*/ |
36
|
5 |
|
public function __destruct() |
37
|
|
|
{ |
38
|
5 |
|
unset($this->emitterBlocked); |
39
|
5 |
|
unset($this->eventPointers); |
40
|
5 |
|
unset($this->eventListeners); |
41
|
5 |
|
unset($this->forwardListeners); |
42
|
5 |
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @see EventEmitterInterface::setMode |
46
|
|
|
*/ |
47
|
20 |
|
public function setMode($emitterMode) |
48
|
|
|
{ |
49
|
20 |
|
$this->emitterBlocked = $emitterMode; |
50
|
20 |
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @see EventEmitterInterface::getMode |
54
|
|
|
*/ |
55
|
4 |
|
public function getMode() |
56
|
|
|
{ |
57
|
4 |
|
return $this->emitterBlocked; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @see EventEmitterInterface::on |
62
|
|
|
*/ |
63
|
66 |
View Code Duplication |
public function on($event, callable $listener) |
|
|
|
|
64
|
|
|
{ |
65
|
66 |
|
if (!isset($this->eventListeners[$event])) |
66
|
|
|
{ |
67
|
66 |
|
$this->eventPointers[$event] = 0; |
68
|
66 |
|
$this->eventListeners[$event] = []; |
69
|
|
|
} |
70
|
|
|
|
71
|
66 |
|
$pointer = &$this->eventPointers[$event]; |
72
|
66 |
|
$eventListener = new EventListener($this, $event, $listener, $this->attachOnListener($pointer, $event, $listener)); |
73
|
|
|
|
74
|
66 |
|
$this->eventListeners[$event][$pointer++] = $eventListener; |
75
|
|
|
|
76
|
66 |
|
return $eventListener; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @see EventEmitterInterface::once |
81
|
|
|
*/ |
82
|
12 |
View Code Duplication |
public function once($event, callable $listener) |
|
|
|
|
83
|
|
|
{ |
84
|
12 |
|
if (!isset($this->eventListeners[$event])) |
85
|
|
|
{ |
86
|
12 |
|
$this->eventPointers[$event] = 0; |
87
|
12 |
|
$this->eventListeners[$event] = []; |
88
|
|
|
} |
89
|
|
|
|
90
|
12 |
|
$pointer = &$this->eventPointers[$event]; |
91
|
12 |
|
$eventListener = new EventListener($this, $event, $listener, $this->attachOnceListener($pointer, $event, $listener)); |
92
|
|
|
|
93
|
12 |
|
$this->eventListeners[$event][$pointer++] = $eventListener; |
94
|
|
|
|
95
|
12 |
|
return $eventListener; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @see EventEmitterInterface::times |
100
|
|
|
*/ |
101
|
28 |
|
public function times($event, $limit, callable $listener) |
102
|
|
|
{ |
103
|
28 |
|
if ($limit === 0) |
104
|
|
|
{ |
105
|
|
|
return $this->on($event, $listener); |
106
|
|
|
} |
107
|
|
|
|
108
|
28 |
|
if (!isset($this->eventListeners[$event])) |
109
|
|
|
{ |
110
|
28 |
|
$this->eventPointers[$event] = 0; |
111
|
28 |
|
$this->eventListeners[$event] = []; |
112
|
|
|
} |
113
|
|
|
|
114
|
28 |
|
$pointer = &$this->eventPointers[$event]; |
115
|
28 |
|
$limit = $limit > 0 ? $limit : 1; |
116
|
28 |
|
$eventListener = new EventListener( |
117
|
28 |
|
$this, |
118
|
28 |
|
$event, |
119
|
28 |
|
$listener, |
120
|
28 |
|
$this->attachTimesListener($pointer, $event, $limit, $listener) |
121
|
|
|
); |
122
|
|
|
|
123
|
28 |
|
$this->eventListeners[$event][$pointer++] = $eventListener; |
124
|
|
|
|
125
|
28 |
|
return $eventListener; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @see EventEmitterInterface::delay |
130
|
|
|
*/ |
131
|
8 |
|
public function delay($event, $ticks, callable $listener) |
132
|
|
|
{ |
133
|
8 |
|
$counter = 0; |
134
|
|
|
return $this->on($event, function(...$args) use(&$counter, $event, $ticks, $listener) { |
135
|
8 |
|
if (++$counter >= $ticks) |
136
|
|
|
{ |
137
|
8 |
|
$listener(...$args); |
138
|
|
|
} |
139
|
8 |
|
}); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* @see EventEmitterInterface::delayOnce |
144
|
|
|
*/ |
145
|
8 |
View Code Duplication |
public function delayOnce($event, $ticks, callable $listener) |
|
|
|
|
146
|
|
|
{ |
147
|
8 |
|
$counter = 0; |
148
|
|
|
return $this->times($event, $ticks, function(...$args) use(&$counter, $event, $ticks, $listener) { |
149
|
8 |
|
if (++$counter >= $ticks) |
150
|
|
|
{ |
151
|
8 |
|
$listener(...$args); |
152
|
|
|
} |
153
|
8 |
|
}); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @see EventEmitterInterface::delayTimes |
158
|
|
|
*/ |
159
|
8 |
View Code Duplication |
public function delayTimes($event, $ticks, $limit, callable $listener) |
|
|
|
|
160
|
|
|
{ |
161
|
8 |
|
$counter = 0; |
162
|
|
|
return $this->times($event, $ticks+$limit-1, function(...$args) use(&$counter, $event, $ticks, $listener) { |
163
|
8 |
|
if (++$counter >= $ticks) |
164
|
|
|
{ |
165
|
8 |
|
$listener(...$args); |
166
|
|
|
} |
167
|
8 |
|
}); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @see EventEmitterInterface::removeListener |
172
|
|
|
*/ |
173
|
16 |
|
public function removeListener($event, callable $listener) |
174
|
|
|
{ |
175
|
16 |
|
if (isset($this->eventListeners[$event])) |
176
|
|
|
{ |
177
|
12 |
|
if (null !== $index = $this->findListener($event, $listener)); |
178
|
|
|
{ |
179
|
12 |
|
unset($this->eventListeners[$event][$index]); |
180
|
|
|
} |
181
|
|
|
} |
182
|
16 |
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @see EventEmitterInterface::removeListeners |
186
|
|
|
*/ |
187
|
8 |
|
public function removeListeners($event) |
188
|
|
|
{ |
189
|
8 |
|
unset($this->eventPointers[$event]); |
190
|
8 |
|
unset($this->eventListeners[$event]); |
191
|
8 |
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* @see EventEmitterInterface::flushListeners |
195
|
|
|
*/ |
196
|
4 |
|
public function flushListeners() |
197
|
|
|
{ |
198
|
4 |
|
unset($this->eventPointers); |
199
|
4 |
|
unset($this->eventListeners); |
200
|
|
|
|
201
|
4 |
|
$this->eventPointers = []; |
202
|
4 |
|
$this->eventListeners = []; |
203
|
4 |
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* @see EventEmitterInterface::findListener |
207
|
|
|
*/ |
208
|
16 |
|
public function findListener($event, callable $listener) |
209
|
|
|
{ |
210
|
16 |
|
$listeners = isset($this->eventListeners[$event]) ? $this->eventListeners[$event] : []; |
211
|
|
|
|
212
|
16 |
|
foreach ($listeners as $index=>$eventListener) |
213
|
|
|
{ |
214
|
16 |
|
if ($listener === $eventListener->getHandler()) |
215
|
|
|
{ |
216
|
16 |
|
return $index; |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
220
|
4 |
|
return null; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* @see EventEmitterInterface::emit |
225
|
|
|
*/ |
226
|
106 |
|
public function emit($event, $arguments = []) |
227
|
|
|
{ |
228
|
106 |
|
$listeners = isset($this->eventListeners[$event]) ? $this->eventListeners[$event] : []; |
229
|
|
|
|
230
|
106 |
|
if (($this->emitterBlocked & EventEmitter::EVENTS_DISCARD_INCOMING) !== EventEmitter::EVENTS_DISCARD_INCOMING) |
231
|
|
|
{ |
232
|
102 |
|
foreach ($listeners as $eventListener) |
233
|
|
|
{ |
234
|
|
|
$listener = isset($eventListener->listener) ? $eventListener->listener : function() {}; |
235
|
94 |
|
$listener(...$arguments); |
236
|
|
|
} |
237
|
|
|
} |
238
|
|
|
|
239
|
106 |
|
if (($this->emitterBlocked & EventEmitter::EVENTS_DISCARD_OUTCOMING) !== EventEmitter::EVENTS_DISCARD_OUTCOMING) |
240
|
|
|
{ |
241
|
98 |
|
foreach ($this->forwardListeners as $listener) |
242
|
|
|
{ |
243
|
16 |
|
$listener->emit($event, $arguments); |
244
|
|
|
} |
245
|
|
|
} |
246
|
106 |
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* @see EventEmitterInterface::copyEvent |
250
|
|
|
*/ |
251
|
8 |
|
public function copyEvent(EventEmitterInterface $emitter, $event) |
252
|
|
|
{ |
253
|
|
|
return $this->on($event, function() use($emitter, $event) { |
254
|
8 |
|
$emitter->emit($event, func_get_args()); |
255
|
8 |
|
}); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* @see EventEmitterInterface::copyEvents |
260
|
|
|
*/ |
261
|
4 |
|
public function copyEvents(EventEmitterInterface $emitter, $events) |
262
|
|
|
{ |
263
|
4 |
|
$handlers = []; |
264
|
4 |
|
$events = (array) $events; |
265
|
|
|
|
266
|
4 |
|
foreach ($events as $event) |
267
|
|
|
{ |
268
|
4 |
|
$handlers[] = $this->copyEvent($emitter, $event); |
269
|
|
|
} |
270
|
|
|
|
271
|
4 |
|
return $handlers; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* @see EventEmitterInterface::forwardEvents |
276
|
|
|
*/ |
277
|
24 |
|
public function forwardEvents(EventEmitterInterface $emitter) |
278
|
|
|
{ |
279
|
24 |
|
$this->forwardListeners[] = $emitter; |
280
|
|
|
|
281
|
24 |
|
return $emitter; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* @see EventEmitterInterface::discardEvents |
286
|
|
|
*/ |
287
|
8 |
|
public function discardEvents(EventEmitterInterface $emitter) |
288
|
|
|
{ |
289
|
8 |
|
foreach ($this->forwardListeners as $index=>$listener) |
290
|
|
|
{ |
291
|
4 |
|
if ($listener === $emitter) |
292
|
|
|
{ |
293
|
4 |
|
unset($this->forwardListeners[$index]); |
294
|
|
|
} |
295
|
|
|
} |
296
|
|
|
|
297
|
8 |
|
return $emitter; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* @param int $pointer |
302
|
|
|
* @param string $event |
303
|
|
|
* @param callable $listener |
304
|
|
|
* @return callable |
305
|
|
|
*/ |
306
|
50 |
|
protected function attachOnListener($pointer, $event, callable $listener) |
|
|
|
|
307
|
|
|
{ |
308
|
50 |
|
return $listener; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* @param int $pointer |
313
|
|
|
* @param string $event |
314
|
|
|
* @param callable $listener |
315
|
|
|
* @return callable |
316
|
|
|
*/ |
317
|
6 |
|
protected function attachOnceListener($pointer, $event, callable $listener) |
318
|
|
|
{ |
319
|
6 |
|
$emitter = $this; |
320
|
|
|
return function(...$args) use($emitter, $listener, $event, $pointer) { |
321
|
6 |
|
unset($emitter->eventListeners[$event][$pointer]); |
322
|
|
|
|
323
|
6 |
|
return $listener(...$args); |
324
|
6 |
|
}; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* @param int $pointer |
329
|
|
|
* @param string $event |
330
|
|
|
* @param int $limit |
331
|
|
|
* @param callable $listener |
332
|
|
|
* @return callable |
333
|
|
|
*/ |
334
|
14 |
|
protected function attachTimesListener($pointer, $event, $limit, callable $listener) |
335
|
|
|
{ |
336
|
14 |
|
$emitter = $this; |
337
|
14 |
|
return function(...$args) use($emitter, $listener, $event, $pointer, &$limit) { |
338
|
14 |
|
if (--$limit === 0) |
339
|
|
|
{ |
340
|
14 |
|
unset($limit); |
341
|
14 |
|
unset($emitter->eventListeners[$event][$pointer]); |
342
|
|
|
} |
343
|
14 |
|
return $listener(...$args); |
344
|
14 |
|
}; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* Destruct method. |
349
|
|
|
*/ |
350
|
|
|
private function destructEventEmitterTrait() |
|
|
|
|
351
|
|
|
{ |
352
|
|
|
$this->emitterBlocked = EventEmitter::EVENTS_FORWARD; |
353
|
|
|
$this->eventPointers = []; |
354
|
|
|
$this->eventListeners = []; |
355
|
|
|
$this->forwardListeners = []; |
356
|
|
|
} |
357
|
|
|
} |
358
|
|
|
|
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.