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 RemoveBraces 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 RemoveBraces, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class RemoveBraces extends AbstractPass |
||
17 | { |
||
18 | /** |
||
19 | * @var array Offsets of braces that need to be preserved (offsets used as keys) |
||
20 | */ |
||
21 | protected $preservedBraces; |
||
22 | |||
23 | /** |
||
24 | * {@inheritdoc} |
||
25 | */ |
||
26 | 39 | protected function optimizeStream() |
|
45 | |||
46 | /** |
||
47 | * Test whether the given structure's braces can be removed |
||
48 | * |
||
49 | * @param array $structure |
||
50 | * @return bool |
||
51 | */ |
||
52 | 35 | protected function canRemoveBracesFrom(array $structure) |
|
56 | |||
57 | /** |
||
58 | * Test whether the token at current offset is a control structure |
||
59 | * |
||
60 | * NOTE: we ignore T_DO since the braces are not optional |
||
61 | * |
||
62 | * @return bool |
||
63 | */ |
||
64 | 39 | protected function isControlStructure() |
|
68 | |||
69 | /** |
||
70 | * Test whether the token at current offset is an open curly brace |
||
71 | * |
||
72 | * @return bool |
||
73 | */ |
||
74 | 35 | protected function isCurlyOpen() |
|
78 | |||
79 | /** |
||
80 | * Test whether current token is followed by a function or class-related declaration |
||
81 | * |
||
82 | * @return bool |
||
83 | */ |
||
84 | 37 | protected function isFollowedByDeclaraction() |
|
96 | |||
97 | /** |
||
98 | * Optimize given T_ELSE structure |
||
99 | * |
||
100 | * @param array $structure |
||
101 | * @return void |
||
102 | */ |
||
103 | 21 | protected function optimizeElse(array $structure) |
|
118 | |||
119 | /** |
||
120 | * Optimize given structure and the other structures it contains |
||
121 | * |
||
122 | * @param array $structure |
||
123 | * @return void |
||
124 | */ |
||
125 | 35 | protected function optimizeStructure(array $structure) |
|
143 | |||
144 | /** |
||
145 | * Optimize a list of parsed structures |
||
146 | * |
||
147 | * @param array[] $structures |
||
148 | * @return void |
||
149 | */ |
||
150 | 39 | protected function optimizeStructures(array $structures) |
|
157 | |||
158 | /** |
||
159 | * Parse the control structure starting at current offset |
||
160 | * |
||
161 | * @return array|false |
||
162 | */ |
||
163 | 39 | protected function parseControlStructure() |
|
232 | |||
233 | /** |
||
234 | * Mark the offset of right braces that must be preserved |
||
235 | * |
||
236 | * Works by counting the number of consecutive braces between the starting point and the next |
||
237 | * non-brace token. If the next token is a T_ELSE or T_ELSEIF and it does not immediately follow |
||
238 | * current brace then its branch belongs to another conditional, which means the brace must be |
||
239 | * preserved |
||
240 | * |
||
241 | * @param integer $offset Offset of the first closing brace |
||
242 | * @return void |
||
243 | */ |
||
244 | 31 | protected function markPreservedBraces($offset) |
|
269 | |||
270 | /** |
||
271 | * Remove braces from given structure |
||
272 | * |
||
273 | * @param array $structure |
||
274 | * @return void |
||
275 | */ |
||
276 | 31 | protected function removeBraces(array $structure) |
|
302 | |||
303 | /** |
||
304 | * Remove the whitespace before given offset, if possible |
||
305 | * |
||
306 | * @return void |
||
307 | */ |
||
308 | 31 | protected function removeWhitespaceBefore($offset) |
|
321 | |||
322 | /** |
||
323 | * Skip the condition of a control structure |
||
324 | * |
||
325 | * @return void |
||
326 | */ |
||
327 | 39 | protected function skipParenthesizedExpression() |
|
358 | |||
359 | /** |
||
360 | * Remove one tab's worth of indentation off a range of PHP tokens |
||
361 | * |
||
362 | * @param integer $start Offset of the first token to unindent |
||
363 | * @param integer $end Offset of the last token to unindent |
||
364 | * @return void |
||
365 | */ |
||
366 | 7 | protected function unindentBlock($start, $end) |
|
382 | } |