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 Co 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 Co, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
13 | class Co |
||
14 | { |
||
15 | |||
16 | /** |
||
17 | * Special constants used for Generator yielding keys. |
||
18 | * |
||
19 | * @const Co::RETURN_WITH Treat yielded value as returned value. |
||
20 | * This is for PHP 5.5 ~ 5.6. |
||
21 | * @const Co::UNSAFE Allow current yield to throw Exceptions. |
||
22 | * @const Co::SAFE Forbid current yield to throw Exceptions. |
||
23 | * Exceptions are just to be returned. |
||
24 | */ |
||
25 | const RETURN_WITH = '__RETURN_WITH__'; |
||
26 | const RETURN_ = '__RETURN_WITH__'; // alias |
||
27 | const RET = '__RETURN_WITH__'; // alias |
||
28 | const RTN = '__RETURN_WITH__'; // alias |
||
29 | const UNSAFE = '__UNSAFE__'; |
||
30 | const SAFE = '__SAFE__'; |
||
31 | |||
32 | /** |
||
33 | * Static default options. |
||
34 | */ |
||
35 | private static $defaults = array( |
||
36 | 'throw' => true, // Throw CURLExceptions? |
||
37 | 'pipeline' => false, // Use HTTP/1.1 pipelining? |
||
38 | 'multiplex' => true, // Use HTTP/2 multiplexing? |
||
39 | 'interval' => 0.5, // curl_multi_select() timeout |
||
40 | 'concurrency' => 6, // Limit of TCP connections |
||
41 | ); |
||
42 | |||
43 | /** |
||
44 | * Execution instance is stored here. |
||
45 | */ |
||
46 | private static $self; |
||
47 | |||
48 | /** |
||
49 | * Instance properties |
||
50 | * |
||
51 | * *Stack ID* means... |
||
52 | * - Generator ID |
||
53 | * - "wait" (Co::wait calls) |
||
54 | * - "async" (Co::async calls) |
||
55 | */ |
||
56 | private $options = array(); |
||
57 | private $mh; // curl_multi_init() |
||
58 | private $count = 0; // count(curl_multi_add_handle called) |
||
59 | private $queue = array(); // cURL resources over concurrency limits are temporalily stored here |
||
60 | private $tree = array(); // array<*Stack ID*, mixed> |
||
61 | private $values = array(); // array<*Stack ID*|*cURL ID*, Generator|resource<cURL>> |
||
62 | private $value_to_parent = array(); // array<*Stack ID*|*cURL ID*, *Stack ID*> |
||
63 | private $value_to_children = array(); // array<*Stack ID*, array<*Stack ID*|*cURL ID*, true>> |
||
64 | private $value_to_keylist = array(); // array<*Stack ID*|*cURL ID*, array<mixed>> |
||
65 | |||
66 | /** |
||
67 | * Override or get default settings. |
||
68 | * |
||
69 | * @access public |
||
70 | * @static |
||
71 | * @param array<string, mixed> $options |
||
72 | */ |
||
73 | public static function setDefaultOptions(array $options) |
||
81 | |||
82 | /** |
||
83 | * Wait all cURL requests to be completed. |
||
84 | * Options override static defaults. |
||
85 | * |
||
86 | * |
||
87 | * @access public |
||
88 | * @static |
||
89 | * @param mixed $value |
||
90 | * @param array<string, mixed> $options |
||
91 | * @see self::__construct() |
||
92 | */ |
||
93 | public static function wait($value, array $options = array()) |
||
120 | |||
121 | /** |
||
122 | * Parallel execution along with Co::async(). |
||
123 | * This method is mainly expected to be used in CURLOPT_WRITEFUNCTION callback. |
||
124 | * |
||
125 | * @access public |
||
126 | * @static |
||
127 | * @param mixed $value |
||
128 | * @see self::__construct() |
||
129 | */ |
||
130 | public static function async($value) |
||
141 | |||
142 | /** |
||
143 | * Internal constructor. |
||
144 | * |
||
145 | * @access private |
||
146 | * @param array<string, mixed> $options |
||
147 | * @see self::initialize(), self::run() |
||
148 | */ |
||
149 | private function __construct(array $options) |
||
158 | |||
159 | /** |
||
160 | * Call curl_multi_add_handle or push into waiting queue. |
||
161 | * |
||
162 | * @access private |
||
163 | * @param resource<cURL> $curl |
||
1 ignored issue
–
show
|
|||
164 | */ |
||
165 | private function enqueue($curl) |
||
188 | |||
189 | /** |
||
190 | * Set or overwrite tree of return values. |
||
191 | * |
||
192 | * @access private |
||
193 | * @param mixed $value mixed |
||
194 | * @param string $parent_hash *Stack ID* |
||
195 | * @param array<string>? $keylist Queue of keys for its hierarchy. |
||
1 ignored issue
–
show
|
|||
196 | */ |
||
197 | private function setTree($value, $parent_hash, array $keylist = array()) |
||
208 | |||
209 | /** |
||
210 | * Unset tree of return values. |
||
211 | * |
||
212 | * @access private |
||
213 | * @param string $hash *Stack ID* or *cURL ID* |
||
214 | */ |
||
215 | private function unsetTree($hash) |
||
226 | |||
227 | /** |
||
228 | * Set table of dependencies. |
||
229 | * |
||
230 | * @access private |
||
231 | * @param Generator|resource<cURL> $value |
||
1 ignored issue
–
show
|
|||
232 | * @param string $parent_hash *Stack ID* or *cURL ID* |
||
233 | * @param array? $keylist Queue of keys for its hierarchy. |
||
1 ignored issue
–
show
|
|||
234 | */ |
||
235 | private function setTable($value, $parent_hash, array $keylist = array()) |
||
248 | |||
249 | /** |
||
250 | * Unset table of dependencies. |
||
251 | * |
||
252 | * @access private |
||
253 | * @param string $hash *Stack ID* or *cURL ID* |
||
254 | */ |
||
255 | private function unsetTable($hash) |
||
284 | |||
285 | /** |
||
286 | * Run curl_multi_exec() loop. |
||
287 | * |
||
288 | * @access private |
||
289 | * @see self::updateCurl(), self::enqueue() |
||
290 | */ |
||
291 | private function run() |
||
321 | |||
322 | /** |
||
323 | * Unset table of dependencies. |
||
324 | * |
||
325 | * @access private |
||
326 | * @param mixed $value |
||
327 | * @param string $parent_hash *Stack ID* or *cURL ID* |
||
328 | * @param array? $keylist Queue of keys for its hierarchy. |
||
1 ignored issue
–
show
|
|||
329 | * @return bool Enqueued? |
||
330 | */ |
||
331 | private function initialize($value, $parent_hash, array $keylist = array()) |
||
381 | |||
382 | /** |
||
383 | * Update tree with cURL result. |
||
384 | * |
||
385 | * @access private |
||
386 | * @param resource<cURL> $value |
||
1 ignored issue
–
show
|
|||
387 | * @param int $errno |
||
388 | * @see self::updateGenerator() |
||
389 | */ |
||
390 | private function updateCurl($value, $errno) |
||
422 | |||
423 | /** |
||
424 | * Check current Generator can throw a CURLException. |
||
425 | * |
||
426 | * @access private |
||
427 | * @param Generator $value |
||
428 | * @return bool |
||
429 | */ |
||
430 | private function canThrow(\Generator $value) |
||
447 | |||
448 | /** |
||
449 | * Update tree with updateCurl() result. |
||
450 | * |
||
451 | * @access private |
||
452 | * @param Generator $value |
||
453 | */ |
||
454 | private function updateGenerator(\Generator $value) |
||
484 | |||
485 | /** |
||
486 | * Validate options. |
||
487 | * |
||
488 | * @access private |
||
489 | * @static |
||
490 | * @param array<string, mixed> $options |
||
491 | * @return array<string, mixed> |
||
1 ignored issue
–
show
|
|||
492 | */ |
||
493 | private static function validateOptions($options) |
||
520 | |||
521 | /** |
||
522 | * Normalize value. |
||
523 | * |
||
524 | * @access private |
||
525 | * @static |
||
526 | * @param mixed $value |
||
527 | * @return miexed |
||
528 | */ |
||
529 | private static function normalize($value) |
||
541 | |||
542 | /** |
||
543 | * Check if a Generator is running. |
||
544 | * This method supports psuedo return with Co::RETURN_WITH. |
||
545 | * |
||
546 | * @access private |
||
547 | * @static |
||
548 | * @param Generator $value |
||
549 | * @return bool |
||
550 | */ |
||
551 | private static function isGeneratorRunning(\Generator $value) |
||
556 | |||
557 | /** |
||
558 | * Get return value from a Generator. |
||
559 | * This method supports psuedo return with Co::RETURN_WITH. |
||
560 | * |
||
561 | * @access private |
||
562 | * @static |
||
563 | * @param Generator $value |
||
564 | * @return bool |
||
565 | */ |
||
566 | private static function getGeneratorReturn(\Generator $value) |
||
577 | |||
578 | /** |
||
579 | * Check if value is a valid cURL resource. |
||
580 | * |
||
581 | * @access private |
||
582 | * @static |
||
583 | * @param mixed $value |
||
584 | * @return bool |
||
585 | */ |
||
586 | private static function isCurl($value) |
||
590 | |||
591 | /** |
||
592 | * Check if value is a valid Generator. |
||
593 | * |
||
594 | * @access private |
||
595 | * @static |
||
596 | * @param mixed $value |
||
597 | * @return bool |
||
598 | */ |
||
599 | private static function isGenerator($value) |
||
603 | |||
604 | /** |
||
605 | * Check if value is a valid array or Traversable, not a Generator. |
||
606 | * |
||
607 | * @access private |
||
608 | * @static |
||
609 | * @param mixed $value |
||
610 | * @return bool |
||
611 | */ |
||
612 | private static function isArrayLike($value) |
||
617 | |||
618 | /** |
||
619 | * Flatten an array or a Traversable. |
||
620 | * |
||
621 | * @access private |
||
622 | * @static |
||
623 | * @param mixed $value |
||
624 | * @param array &$carry |
||
625 | * @return array<mixed> |
||
626 | */ |
||
627 | private static function flatten($value, &$carry = array()) |
||
638 | |||
639 | } |
||
640 |
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.