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 classes like SelectLoop 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 SelectLoop, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
13 | class SelectLoop implements LoopModelInterface |
||
14 | { |
||
15 | /** |
||
16 | * @var int |
||
17 | */ |
||
18 | const MICROSECONDS_PER_SECOND = 1e6; |
||
19 | |||
20 | /** |
||
21 | * @var TickContinousQueue |
||
22 | */ |
||
23 | protected $startTickQueue; |
||
24 | |||
25 | /** |
||
26 | * @var TickContinousQueue |
||
27 | */ |
||
28 | protected $stopTickQueue; |
||
29 | |||
30 | /** |
||
31 | * @var TickContinousQueue |
||
32 | */ |
||
33 | protected $nextTickQueue; |
||
34 | |||
35 | /** |
||
36 | * @var TickFiniteQueue |
||
37 | */ |
||
38 | protected $futureTickQueue; |
||
39 | |||
40 | /** |
||
41 | * @var FlowController |
||
42 | */ |
||
43 | protected $flowController; |
||
44 | |||
45 | /** |
||
46 | * @var TimerBox |
||
47 | */ |
||
48 | protected $timers; |
||
49 | |||
50 | /** |
||
51 | * @var resource[] |
||
52 | */ |
||
53 | protected $readStreams = []; |
||
54 | |||
55 | /** |
||
56 | * @var callable[] |
||
57 | */ |
||
58 | protected $readListeners = []; |
||
59 | |||
60 | /** |
||
61 | * @var resource[] |
||
62 | */ |
||
63 | protected $writeStreams = []; |
||
64 | |||
65 | /** |
||
66 | * @var callable[] |
||
67 | */ |
||
68 | protected $writeListeners = []; |
||
69 | |||
70 | /** |
||
71 | * |
||
72 | */ |
||
73 | 55 | public function __construct() |
|
82 | |||
83 | /** |
||
84 | * |
||
85 | */ |
||
86 | 3 | public function __destruct() |
|
99 | |||
100 | /** |
||
101 | * @override |
||
102 | * @inheritDoc |
||
103 | */ |
||
104 | 12 | public function isRunning() |
|
108 | |||
109 | /** |
||
110 | * @override |
||
111 | * @inheritDoc |
||
112 | */ |
||
113 | 14 | View Code Duplication | public function addReadStream($stream, callable $listener) |
123 | |||
124 | /** |
||
125 | * @override |
||
126 | * @inheritDoc |
||
127 | */ |
||
128 | 14 | View Code Duplication | public function addWriteStream($stream, callable $listener) |
138 | |||
139 | /** |
||
140 | * @override |
||
141 | * @inheritDoc |
||
142 | */ |
||
143 | 10 | public function removeReadStream($stream) |
|
152 | |||
153 | /** |
||
154 | * @override |
||
155 | * @inheritDoc |
||
156 | */ |
||
157 | 14 | public function removeWriteStream($stream) |
|
166 | |||
167 | /** |
||
168 | * @override |
||
169 | * @inheritDoc |
||
170 | */ |
||
171 | 6 | public function removeStream($stream) |
|
176 | |||
177 | /** |
||
178 | * @override |
||
179 | * @inheritDoc |
||
180 | */ |
||
181 | 8 | public function addTimer($interval, callable $callback) |
|
189 | |||
190 | /** |
||
191 | * @override |
||
192 | * @inheritDoc |
||
193 | */ |
||
194 | 10 | public function addPeriodicTimer($interval, callable $callback) |
|
202 | |||
203 | /** |
||
204 | * @override |
||
205 | * @inheritDoc |
||
206 | */ |
||
207 | 4 | public function cancelTimer(TimerInterface $timer) |
|
214 | |||
215 | /** |
||
216 | * @override |
||
217 | * @inheritDoc |
||
218 | */ |
||
219 | 4 | public function isTimerActive(TimerInterface $timer) |
|
223 | |||
224 | /** |
||
225 | * @override |
||
226 | * @inheritDoc |
||
227 | */ |
||
228 | 2 | public function onStart(callable $listener) |
|
232 | |||
233 | /** |
||
234 | * @override |
||
235 | * @inheritDoc |
||
236 | */ |
||
237 | 2 | public function onStop(callable $listener) |
|
241 | |||
242 | /** |
||
243 | * @override |
||
244 | * @inheritDoc |
||
245 | */ |
||
246 | 8 | public function onBeforeTick(callable $listener) |
|
250 | |||
251 | /** |
||
252 | * @override |
||
253 | * @inheritDoc |
||
254 | */ |
||
255 | 14 | public function onAfterTick(callable $listener) |
|
259 | |||
260 | /** |
||
261 | * @override |
||
262 | * @inheritDoc |
||
263 | */ |
||
264 | 28 | public function tick() |
|
275 | |||
276 | /** |
||
277 | * @override |
||
278 | * @inheritDoc |
||
279 | */ |
||
280 | 10 | public function start() |
|
328 | |||
329 | /** |
||
330 | * @override |
||
331 | * @inheritDoc |
||
332 | */ |
||
333 | 14 | public function stop() |
|
343 | |||
344 | /** |
||
345 | * @override |
||
346 | * @inheritDoc |
||
347 | */ |
||
348 | 2 | public function setFlowController($flowController) |
|
352 | |||
353 | /** |
||
354 | * @override |
||
355 | * @inheritDoc |
||
356 | */ |
||
357 | 4 | public function getFlowController() |
|
361 | |||
362 | /** |
||
363 | * @override |
||
364 | * @inheritDoc |
||
365 | */ |
||
366 | 4 | public function erase($all = false) |
|
381 | |||
382 | /** |
||
383 | * @override |
||
384 | * @inheritDoc |
||
385 | */ |
||
386 | View Code Duplication | public function export(LoopModelInterface $loop, $all = false) |
|
399 | |||
400 | /** |
||
401 | * @override |
||
402 | * @inheritDoc |
||
403 | */ |
||
404 | View Code Duplication | public function import(LoopModelInterface $loop, $all = false) |
|
417 | |||
418 | /** |
||
419 | * @override |
||
420 | * @inheritDoc |
||
421 | */ |
||
422 | public function swap(LoopModelInterface $loop, $all = false) |
||
437 | |||
438 | /** |
||
439 | * Wait/check for stream activity, or until the next timer is due. |
||
440 | * |
||
441 | * @param float $timeout |
||
442 | */ |
||
443 | 38 | private function waitForStreamActivity($timeout) |
|
475 | |||
476 | /** |
||
477 | * Emulate a stream_select() implementation that does not break when passed empty stream arrays. |
||
478 | * |
||
479 | * @param array &$read |
||
480 | * @param array &$write |
||
481 | * @param integer|null $timeout |
||
482 | * |
||
483 | * @return integer The total number of streams that are ready for read/write. |
||
484 | */ |
||
485 | 38 | private function streamSelect(array &$read, array &$write, $timeout) |
|
498 | |||
499 | /** |
||
500 | * Get list of properties that can be exported/imported safely. |
||
501 | * |
||
502 | * @return array |
||
503 | */ |
||
504 | 2 | private function getTransferableProperties() |
|
512 | } |
||
513 |
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.