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 UserStatistics 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 UserStatistics, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class UserStatistics extends Model |
||
12 | { |
||
13 | /** |
||
14 | * Get the user's statistics. |
||
15 | * |
||
16 | * @return Array of Statistics. |
||
17 | */ |
||
18 | public function getStatistics() |
||
26 | |||
27 | /** |
||
28 | * Get a statistic. |
||
29 | * |
||
30 | * @param $typeCode code of the category type. |
||
31 | * @param $categoryCode code of the statistical category. |
||
32 | * |
||
33 | * @return Statistic. |
||
34 | */ |
||
35 | public function getStatistic($typeCode,$categoryCode) |
||
46 | |||
47 | /** |
||
48 | * Add a user statistic with no regard to existing Types and Categories. |
||
49 | * |
||
50 | * @param string $typeCode code of the category type. |
||
51 | * @param string $typeDesc description of the category type. |
||
52 | * @param string $categoryCode code of the statistical category. |
||
53 | * @param string $categoryDesc description of the statistical category. |
||
54 | * @param string $note free text description of the statistic. |
||
55 | * @param string $segment_type (Internal|External) |
||
56 | * |
||
57 | * @return Statistic |
||
58 | */ |
||
59 | public function addStatisticRaw($typeCode,$typeDesc,$categoryCode,$categoryDesc,$segment_type,$note) |
||
82 | |||
83 | /** |
||
84 | * Add a user statistic based upon existing Types and Categories. |
||
85 | * |
||
86 | * @param string $typeCode code of the category type. |
||
87 | * @param string $categoryCode code of the statistical category. |
||
88 | * |
||
89 | * @return Statistic |
||
90 | */ |
||
91 | public function addStatistic($typeCode,$categoryCode,$segmentType,$note) |
||
122 | |||
123 | /** |
||
124 | * Delete a user statistic. |
||
125 | * |
||
126 | * @param string $typeCode code of the category type. |
||
127 | * @param string $categoryCode code of the statistical category. |
||
128 | */ |
||
129 | public function removeStatistic($typeCode,$categoryCode) |
||
141 | |||
142 | /** |
||
143 | * Update a user statistic. |
||
144 | * |
||
145 | */ |
||
146 | public function updateStatistic($fromTypeCode,$fromCategoryCode,$toTypeCode,$toCategoryCode,$segementType,$note) |
||
152 | |||
153 | /** |
||
154 | * Get Stats By Type Code. |
||
155 | * |
||
156 | * @return Array of Statistics. |
||
157 | */ |
||
158 | View Code Duplication | public function getStatsByTypeCode($typeCode) |
|
169 | |||
170 | /** |
||
171 | * Get Stats by Type Desc. |
||
172 | * |
||
173 | * @return Array of statistics. |
||
174 | */ |
||
175 | View Code Duplication | public function getStatsByTypeDesc($typeDesc) |
|
185 | |||
186 | /** |
||
187 | * Get Stats by Category Code. |
||
188 | * |
||
189 | * @return Array of Statistics. |
||
190 | */ |
||
191 | View Code Duplication | public function getStatsByCategoryCode($categoryCode) |
|
201 | |||
202 | /** |
||
203 | * Get Stats by Category Desc. |
||
204 | * |
||
205 | * @return Array of Statistics. |
||
206 | */ |
||
207 | View Code Duplication | public function getStatsByCategoryDesc($categoryDesc) |
|
217 | |||
218 | /** |
||
219 | * Get Stats by Segment Type. |
||
220 | * |
||
221 | * @return Array of Statistics. |
||
222 | */ |
||
223 | public function getStatsBySegmentType($segmentType) |
||
233 | |||
234 | /** |
||
235 | * Search Stats by Note. |
||
236 | * |
||
237 | * @return Array of Statistics. |
||
238 | */ |
||
239 | public function searchStatsByNote($note) |
||
249 | |||
250 | /** |
||
251 | * Search Stats by Type Code. |
||
252 | * |
||
253 | * @return Array of Statistics. |
||
254 | */ |
||
255 | View Code Duplication | public function searchStatsByTypeCode($typeCode) |
|
265 | |||
266 | /** |
||
267 | * Search Stats by Type Code. |
||
268 | * |
||
269 | * @return Array of Statistics. |
||
270 | */ |
||
271 | View Code Duplication | public function searchStatsByTypeDesc($typeDesc) |
|
281 | |||
282 | /** |
||
283 | * Search Stats by Type Code. |
||
284 | * |
||
285 | * @return Array of Statistics. |
||
286 | */ |
||
287 | View Code Duplication | public function searchStatsByCategoryCode($categoryCode) |
|
297 | |||
298 | /** |
||
299 | * Search Stats by Type Code. |
||
300 | * |
||
301 | * @return Array of Statistics. |
||
302 | */ |
||
303 | View Code Duplication | public function searchStatsByCategoryDesc($categoryDesc) |
|
313 | |||
314 | } |
||
315 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.