@@ -22,6 +22,22 @@ class EventManager implements EventManagerInterface
22
22
/**
23
23
* Subscribed events and their listeners
24
24
*
25
+ * STRUCTURE:
26
+ * [
27
+ * <string name> => [
28
+ * <int priority> => [
29
+ * 0 => [<callable listener>, ...]
30
+ * ],
31
+ * ...
32
+ * ],
33
+ * ...
34
+ * ]
35
+ *
36
+ * NOTE:
37
+ * This structure helps us to reuse the list of listeners
38
+ * instead of first iterating over it and generating a new one
39
+ * -> In result it improves performance by up to 25% even if it looks a bit strange
40
+ *
25
41
* @var array[]
26
42
*/
27
43
protected $ events = [];
@@ -116,8 +132,14 @@ public function trigger($eventName, $target = null, $argv = [])
116
132
{
117
133
$ event = clone $ this ->eventPrototype ;
118
134
$ event ->setName ($ eventName );
119
- $ event ->setTarget ($ target );
120
- $ event ->setParams ($ argv );
135
+
136
+ if ($ target !== null ) {
137
+ $ event ->setTarget ($ target );
138
+ }
139
+
140
+ if ($ argv ) {
141
+ $ event ->setParams ($ argv );
142
+ }
121
143
122
144
return $ this ->triggerListeners ($ event );
123
145
}
@@ -129,8 +151,14 @@ public function triggerUntil(callable $callback, $eventName, $target = null, $ar
129
151
{
130
152
$ event = clone $ this ->eventPrototype ;
131
153
$ event ->setName ($ eventName );
132
- $ event ->setTarget ($ target );
133
- $ event ->setParams ($ argv );
154
+
155
+ if ($ target !== null ) {
156
+ $ event ->setTarget ($ target );
157
+ }
158
+
159
+ if ($ argv ) {
160
+ $ event ->setParams ($ argv );
161
+ }
134
162
135
163
return $ this ->triggerListeners ($ event , $ callback );
136
164
}
@@ -164,8 +192,7 @@ public function attach($eventName, callable $listener, $priority = 1)
164
192
));
165
193
}
166
194
167
- $ this ->events [$ eventName ][((int ) $ priority ) . '.0 ' ][] = $ listener ;
168
-
195
+ $ this ->events [$ eventName ][(int ) $ priority ][0 ][] = $ listener ;
169
196
return $ listener ;
170
197
}
171
198
@@ -197,36 +224,35 @@ public function detach(callable $listener, $eventName = null, $force = false)
197
224
}
198
225
199
226
foreach ($ this ->events [$ eventName ] as $ priority => $ listeners ) {
200
- foreach ($ listeners as $ index => $ evaluatedListener ) {
227
+ foreach ($ listeners[ 0 ] as $ index => $ evaluatedListener ) {
201
228
if ($ evaluatedListener !== $ listener ) {
202
229
continue ;
203
230
}
204
231
205
232
// Found the listener; remove it.
206
- unset($ this ->events [$ eventName ][$ priority ][$ index ]);
233
+ unset($ this ->events [$ eventName ][$ priority ][0 ][ $ index ]);
207
234
208
235
// If the queue for the given priority is empty, remove it.
209
- if (empty ($ this ->events [$ eventName ][$ priority ])) {
236
+ if (empty ($ this ->events [$ eventName ][$ priority ][ 0 ] )) {
210
237
unset($ this ->events [$ eventName ][$ priority ]);
211
238
break ;
212
239
}
213
240
}
241
+ }
214
242
215
- // If the queue for the given event is empty, remove it.
216
- if (empty ($ this ->events [$ eventName ])) {
217
- unset($ this ->events [$ eventName ]);
218
- break ;
219
- }
243
+ // If the queue for the given event is empty, remove it.
244
+ if (empty ($ this ->events [$ eventName ])) {
245
+ unset($ this ->events [$ eventName ]);
220
246
}
221
247
}
222
248
223
249
/**
224
250
* @inheritDoc
225
251
*/
226
- public function clearListeners ($ event )
252
+ public function clearListeners ($ eventName )
227
253
{
228
- if (isset ($ this ->events [$ event ])) {
229
- unset($ this ->events [$ event ]);
254
+ if (isset ($ this ->events [$ eventName ])) {
255
+ unset($ this ->events [$ eventName ]);
230
256
}
231
257
}
232
258
@@ -262,58 +288,56 @@ protected function triggerListeners(EventInterface $event, callable $callback =
262
288
throw new Exception \RuntimeException ('Event is missing a name; cannot trigger! ' );
263
289
}
264
290
265
- // Initial value of stop propagation flag should be false
266
- $ event ->stopPropagation (false );
267
-
268
- $ responses = new ResponseCollection ();
291
+ if (isset ($ this ->events [$ name ])) {
292
+ $ listOfListenersByPriority = $ this ->events [$ name ];
269
293
270
- foreach ($ this ->getListenersByEventName ($ name ) as $ listener ) {
271
- $ response = $ listener ($ event );
272
- $ responses ->push ($ response );
273
-
274
- // If the event was asked to stop propagating, do so
275
- if ($ event ->propagationIsStopped ()) {
276
- $ responses ->setStopped (true );
277
- break ;
294
+ if (isset ($ this ->events ['* ' ])) {
295
+ foreach ($ this ->events ['* ' ] as $ priority => $ listOfListeners ) {
296
+ $ listOfListenersByPriority [$ priority ][] = $ listOfListeners [0 ];
297
+ }
278
298
}
299
+ } elseif (isset ($ this ->events ['* ' ])) {
300
+ $ listOfListenersByPriority = $ this ->events ['* ' ];
301
+ } else {
302
+ $ listOfListenersByPriority = [];
303
+ }
279
304
280
- // If the result causes our validation callback to return true,
281
- // stop propagation
282
- if ($ callback && $ callback ($ response )) {
283
- $ responses ->setStopped (true );
284
- break ;
305
+ if ($ this ->sharedManager ) {
306
+ foreach ($ this ->sharedManager ->getListeners ($ this ->identifiers , $ name ) as $ priority => $ listeners ) {
307
+ $ listOfListenersByPriority [$ priority ][] = $ listeners ;
285
308
}
286
309
}
287
310
288
- return $ responses ;
289
- }
290
-
291
- /**
292
- * Get listeners for the currently triggered event.
293
- *
294
- * @param string $eventName
295
- * @return callable[]
296
- */
297
- private function getListenersByEventName ($ eventName )
298
- {
299
- $ listeners = array_merge_recursive (
300
- isset ($ this ->events [$ eventName ]) ? $ this ->events [$ eventName ] : [],
301
- isset ($ this ->events ['* ' ]) ? $ this ->events ['* ' ] : [],
302
- $ this ->sharedManager ? $ this ->sharedManager ->getListeners ($ this ->identifiers , $ eventName ) : []
303
- );
304
-
305
- krsort ($ listeners , SORT_NUMERIC );
311
+ // Sort by priority in reverse order
312
+ krsort ($ listOfListenersByPriority );
306
313
307
- $ listenersForEvent = [];
314
+ // Initial value of stop propagation flag should be false
315
+ $ event ->stopPropagation (false );
308
316
309
- foreach ($ listeners as $ priority => $ listenersByPriority ) {
310
- foreach ($ listenersByPriority as $ listener ) {
311
- // Performance note: after some testing, it appears that accumulating listeners and sending
312
- // them at the end of the method is FASTER than using generators (ie. yielding)
313
- $ listenersForEvent [] = $ listener ;
317
+ // Execute listeners
318
+ $ responses = new ResponseCollection ();
319
+ foreach ($ listOfListenersByPriority as $ listOfListeners ) {
320
+ foreach ($ listOfListeners as $ listeners ) {
321
+ foreach ($ listeners as $ listener ) {
322
+ $ response = $ listener ($ event );
323
+ $ responses ->push ($ response );
324
+
325
+ // If the event was asked to stop propagating, do so
326
+ if ($ event ->propagationIsStopped ()) {
327
+ $ responses ->setStopped (true );
328
+ return $ responses ;
329
+ }
330
+
331
+ // If the result causes our validation callback to return true,
332
+ // stop propagation
333
+ if ($ callback && $ callback ($ response )) {
334
+ $ responses ->setStopped (true );
335
+ return $ responses ;
336
+ }
337
+ }
314
338
}
315
339
}
316
340
317
- return $ listenersForEvent ;
341
+ return $ responses ;
318
342
}
319
343
}
0 commit comments