BaseEventEmitterTrait   B
last analyzed

Complexity

Total Complexity 46

Size/Duplication

Total Lines 353
Duplicated Lines 14.16 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 94.49%

Importance

Changes 0
Metric Value
wmc 46
lcom 1
cbo 2
dl 50
loc 353
ccs 120
cts 127
cp 0.9449
rs 8.3999
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A __destruct() 0 7 1
A setMode() 0 4 1
A getMode() 0 4 1
A on() 15 15 2
A once() 15 15 2
B times() 0 26 4
A delay() 0 10 2
A delayOnce() 10 10 2
A delayTimes() 10 10 2
A removeListener() 0 10 3
A removeListeners() 0 5 1
A flushListeners() 0 8 1
A findListener() 0 14 4
B emit() 0 21 7
A copyEvent() 0 6 1
A copyEvents() 0 12 2
A forwardEvents() 0 6 1
A discardEvents() 0 12 3
A attachOnListener() 0 4 1
A attachOnceListener() 0 9 1
A attachTimesListener() 0 12 2
A destructEventEmitterTrait() 0 7 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BaseEventEmitterTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseEventEmitterTrait, and based on these observations, apply Extract Interface, too.

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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Unused Code introduced by
The parameter $pointer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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()
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
351
    {
352
        $this->emitterBlocked = EventEmitter::EVENTS_FORWARD;
353
        $this->eventPointers = [];
354
        $this->eventListeners = [];
355
        $this->forwardListeners = [];
356
    }
357
}
358