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 ReflectionFile 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 ReflectionFile, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class ReflectionFile extends Component implements ReflectionFileInterface |
||
21 | { |
||
22 | /** |
||
23 | * Development sugar. |
||
24 | */ |
||
25 | use SaturateTrait; |
||
26 | |||
27 | /** |
||
28 | * Namespace separator. |
||
29 | */ |
||
30 | const NS_SEPARATOR = '\\'; |
||
31 | |||
32 | /** |
||
33 | * Constants for convenience. |
||
34 | */ |
||
35 | const TOKEN_TYPE = TokenizerInterface::TYPE; |
||
36 | const TOKEN_CODE = TokenizerInterface::CODE; |
||
37 | const TOKEN_LINE = TokenizerInterface::LINE; |
||
38 | |||
39 | /** |
||
40 | * Opening and closing token ids. |
||
41 | */ |
||
42 | const O_TOKEN = 0; |
||
43 | const C_TOKEN = 1; |
||
44 | |||
45 | /** |
||
46 | * Namespace uses. |
||
47 | */ |
||
48 | const N_USES = 2; |
||
49 | |||
50 | /** |
||
51 | * Set of tokens required to detect classes, traits, interfaces and function declarations. We |
||
52 | * don't need any other token for that. |
||
53 | * |
||
54 | * @var array |
||
55 | */ |
||
56 | static private $processTokens = [ |
||
57 | '{', |
||
58 | '}', |
||
59 | ';', |
||
60 | T_PAAMAYIM_NEKUDOTAYIM, |
||
61 | T_NAMESPACE, |
||
62 | T_STRING, |
||
63 | T_CLASS, |
||
64 | T_INTERFACE, |
||
65 | T_TRAIT, |
||
66 | T_FUNCTION, |
||
67 | T_NS_SEPARATOR, |
||
68 | T_INCLUDE, |
||
69 | T_INCLUDE_ONCE, |
||
70 | T_REQUIRE, |
||
71 | T_REQUIRE_ONCE, |
||
72 | T_USE, |
||
73 | T_AS |
||
74 | ]; |
||
75 | |||
76 | /** |
||
77 | * @var string |
||
78 | */ |
||
79 | private $filename = ''; |
||
80 | |||
81 | /** |
||
82 | * Parsed tokens array. |
||
83 | * |
||
84 | * @invisible |
||
85 | * @var array |
||
86 | */ |
||
87 | private $tokens = []; |
||
88 | |||
89 | /** |
||
90 | * Total tokens count. |
||
91 | * |
||
92 | * @invisible |
||
93 | * @var int |
||
94 | */ |
||
95 | private $countTokens = 0; |
||
96 | |||
97 | /** |
||
98 | * Indicator that file has external includes. |
||
99 | * |
||
100 | * @invisible |
||
101 | * @var bool |
||
102 | */ |
||
103 | private $hasIncludes = false; |
||
104 | |||
105 | /** |
||
106 | * Namespaces used in file and their token positions. |
||
107 | * |
||
108 | * @invisible |
||
109 | * @var array |
||
110 | */ |
||
111 | private $namespaces = []; |
||
112 | |||
113 | /** |
||
114 | * Declarations of classes, interfaces and traits. |
||
115 | * |
||
116 | * @invisible |
||
117 | * @var array |
||
118 | */ |
||
119 | private $declarations = []; |
||
120 | |||
121 | /** |
||
122 | * Declarations of new functions. |
||
123 | * |
||
124 | * @invisible |
||
125 | * @var array |
||
126 | */ |
||
127 | private $functions = []; |
||
128 | |||
129 | /** |
||
130 | * Every found method/function invocation. |
||
131 | * |
||
132 | * @invisible |
||
133 | * @var ReflectionInvocation[] |
||
134 | */ |
||
135 | private $invocations = []; |
||
136 | |||
137 | /** |
||
138 | * @invisible |
||
139 | * @var TokenizerInterface |
||
140 | */ |
||
141 | protected $tokenizer = null; |
||
142 | |||
143 | /** |
||
144 | * @param string $filename |
||
145 | * @param TokenizerInterface $tokenizer |
||
146 | * @param array $cache Tokenizer can construct reflection with pre-created |
||
147 | * cache to speed up indexation. |
||
148 | */ |
||
149 | public function __construct($filename, TokenizerInterface $tokenizer = null, array $cache = []) |
||
164 | |||
165 | /** |
||
166 | * {@inheritdoc} |
||
167 | */ |
||
168 | public function getFilename() |
||
172 | |||
173 | /** |
||
174 | * {@inheritdoc} |
||
175 | */ |
||
176 | public function getFunctions() |
||
180 | |||
181 | /** |
||
182 | * {@inheritdoc} |
||
183 | */ |
||
184 | public function getClasses() |
||
192 | |||
193 | /** |
||
194 | * {@inheritdoc} |
||
195 | */ |
||
196 | public function getTraits() |
||
204 | |||
205 | /** |
||
206 | * {@inheritdoc} |
||
207 | */ |
||
208 | public function getInterfaces() |
||
216 | |||
217 | /** |
||
218 | * Get list of tokens associated with given file. |
||
219 | * |
||
220 | * @return array |
||
221 | */ |
||
222 | public function getTokens() |
||
232 | |||
233 | /** |
||
234 | * {@inheritdoc} |
||
235 | */ |
||
236 | public function hasIncludes() |
||
240 | |||
241 | /** |
||
242 | * {@inheritdoc} |
||
243 | */ |
||
244 | public function getInvocations() |
||
252 | |||
253 | /** |
||
254 | * Export found declaration as array for caching purposes. |
||
255 | * |
||
256 | * @return array |
||
257 | */ |
||
258 | public function exportSchema() |
||
262 | |||
263 | /** |
||
264 | * Import cached reflection schema. |
||
265 | * |
||
266 | * @param array $cache |
||
267 | */ |
||
268 | protected function importSchema(array $cache) |
||
272 | |||
273 | /** |
||
274 | * Locate every class, interface, trait or function definition. |
||
275 | */ |
||
276 | protected function locateDeclarations() |
||
325 | |||
326 | /** |
||
327 | * Handle namespace declaration. |
||
328 | * |
||
329 | * @param int $tokenID |
||
330 | */ |
||
331 | private function registerNamespace($tokenID) |
||
369 | |||
370 | /** |
||
371 | * Handle use (import class from another namespace). |
||
372 | * |
||
373 | * @param int $tokenID |
||
374 | */ |
||
375 | private function registerUse($tokenID) |
||
401 | |||
402 | /** |
||
403 | * Handle function declaration (function creation). |
||
404 | * |
||
405 | * @param int $tokenID |
||
406 | */ |
||
407 | private function registerFunction($tokenID) |
||
434 | |||
435 | /** |
||
436 | * Handle declaration of class, trait of interface. Declaration will be stored under it's token |
||
437 | * type in declarations array. |
||
438 | * |
||
439 | * @param int $tokenID |
||
440 | * @param int $tokenType |
||
441 | */ |
||
442 | private function registerDeclaration($tokenID, $tokenType) |
||
459 | |||
460 | /** |
||
461 | * Locate every function or static method call (including $this calls). |
||
462 | * |
||
463 | * @param array $tokens |
||
464 | * @param int $invocationLevel |
||
465 | */ |
||
466 | private function locateInvocations(array $tokens, $invocationLevel = 0) |
||
585 | |||
586 | /** |
||
587 | * Registering invocation. |
||
588 | * |
||
589 | * @param int $invocationID |
||
590 | * @param int $argumentsID |
||
591 | * @param int $endID |
||
592 | * @param array $arguments |
||
593 | * @param int $invocationLevel |
||
594 | */ |
||
595 | private function registerInvocation( |
||
622 | |||
623 | /** |
||
624 | * Fetching invocation context. |
||
625 | * |
||
626 | * @param int $invocationTID |
||
627 | * @param int $argumentsTID |
||
628 | * @return array |
||
629 | */ |
||
630 | private function fetchContext($invocationTID, $argumentsTID) |
||
653 | |||
654 | /** |
||
655 | * Get declaration which is active in given token position. |
||
656 | * |
||
657 | * @param int $tokenID |
||
658 | * @return string|null |
||
659 | */ |
||
660 | private function activeDeclaration($tokenID) |
||
673 | |||
674 | /** |
||
675 | * Get namespace name active at specified token position. |
||
676 | * |
||
677 | * @param int $tokenID |
||
678 | * @return string |
||
679 | */ |
||
680 | private function activeNamespace($tokenID) |
||
697 | |||
698 | /** |
||
699 | * Find token ID of ending brace. |
||
700 | * |
||
701 | * @param int $tokenID |
||
702 | * @return mixed |
||
703 | */ |
||
704 | private function endingToken($tokenID) |
||
725 | |||
726 | /** |
||
727 | * Get line number associated with token. |
||
728 | * |
||
729 | * @param int $tokenID |
||
730 | * @return int |
||
731 | */ |
||
732 | private function lineNumber($tokenID) |
||
740 | |||
741 | /** |
||
742 | * Get source located between two tokens. |
||
743 | * |
||
744 | * @param int $startID |
||
745 | * @param int $endID |
||
746 | * @return string |
||
747 | */ |
||
748 | private function getSource($startID, $endID) |
||
758 | } |
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break
.To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.