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 Attribute 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 Attribute, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class Attribute extends JsonObject |
||
21 | { |
||
22 | // identifiers for the Api Product Attribute Types: |
||
23 | const T_UNKNOWN = 'unknown'; // zero, should evaluate to false |
||
24 | |||
25 | const PROP_VALUE = "value"; |
||
26 | const PROP_KEY = "key"; |
||
27 | const PROP_NAME = "name"; |
||
28 | const PROP_CURRENCY_CODE = "currencyCode"; |
||
29 | const PROP_CENT_AMOUNT = "centAmount"; |
||
30 | const PROP_TYPE_ID = "typeId"; |
||
31 | const PROP_ID = "id"; |
||
32 | const PROP_LABEL = "label"; |
||
33 | |||
34 | const API_BOOL = 'boolean'; |
||
35 | const API_NUMBER = 'number'; |
||
36 | const API_TEXT = 'text'; |
||
37 | const API_LTEXT = 'ltext'; |
||
38 | const API_LENUM = 'lenum'; |
||
39 | const API_ENUM = 'enum'; |
||
40 | const API_MONEY = 'money'; |
||
41 | const API_DATE = 'date'; |
||
42 | const API_TIME = 'time'; |
||
43 | const API_DATETIME = 'datetime'; |
||
44 | const API_SET = 'set'; |
||
45 | const API_NESTED = 'nested'; |
||
46 | const API_REFERENCE = 'reference'; |
||
47 | |||
48 | protected static $types = []; |
||
49 | |||
50 | 48 | public function fieldDefinitions() |
|
57 | |||
58 | 48 | public function fieldDefinition($field) |
|
76 | |||
77 | /** |
||
78 | * @param $attributeName |
||
79 | * @param $value |
||
80 | * @return mixed |
||
81 | */ |
||
82 | 40 | protected function getApiType($attributeName, $value) |
|
97 | |||
98 | /** |
||
99 | * @param AttributeDefinition $definition |
||
100 | * @return $this |
||
101 | */ |
||
102 | 40 | public function setAttributeDefinition(AttributeDefinition $definition) |
|
108 | |||
109 | /** |
||
110 | * @param string $field |
||
111 | */ |
||
112 | 41 | protected function initialize($field) |
|
121 | |||
122 | 36 | private function setApiType($attributeName, $valueType, $elementType = null) |
|
135 | |||
136 | /** |
||
137 | * @return bool |
||
138 | */ |
||
139 | 1 | public function getValueAsBool() |
|
145 | |||
146 | /** |
||
147 | * @return int|float |
||
148 | */ |
||
149 | 2 | public function getValueAsNumber() |
|
155 | |||
156 | /** |
||
157 | * @return string |
||
158 | */ |
||
159 | 1 | public function getValueAsString() |
|
165 | |||
166 | /** |
||
167 | * @return LocalizedString |
||
168 | */ |
||
169 | 1 | public function getValueAsLocalizedString() |
|
175 | |||
176 | /** |
||
177 | * @return LocalizedEnum |
||
178 | */ |
||
179 | 1 | public function getValueAsLocalizedEnum() |
|
185 | |||
186 | /** |
||
187 | * @return Enum |
||
188 | */ |
||
189 | 1 | public function getValueAsEnum() |
|
195 | |||
196 | /** |
||
197 | * @return Money |
||
198 | */ |
||
199 | 1 | public function getValueAsMoney() |
|
205 | |||
206 | /** |
||
207 | * @return DateDecorator |
||
208 | */ |
||
209 | public function getValueAsDate() |
||
215 | |||
216 | /** |
||
217 | * @return TimeDecorator |
||
218 | */ |
||
219 | public function getValueAsTime() |
||
225 | |||
226 | /** |
||
227 | * @return DateTimeDecorator |
||
228 | */ |
||
229 | public function getValueAsDateTime() |
||
235 | |||
236 | /** |
||
237 | * @return AttributeCollection |
||
238 | */ |
||
239 | 1 | public function getValueAsNested() |
|
245 | |||
246 | /** |
||
247 | * @return Reference |
||
248 | */ |
||
249 | 1 | public function getValueAsReference() |
|
255 | |||
256 | /** |
||
257 | * @return Set |
||
258 | */ |
||
259 | 1 | public function getValueAsBoolSet() |
|
265 | |||
266 | /** |
||
267 | * @return Set |
||
268 | */ |
||
269 | 2 | public function getValueAsNumberSet() |
|
275 | |||
276 | /** |
||
277 | * @return Set |
||
278 | */ |
||
279 | 1 | public function getValueAsStringSet() |
|
285 | |||
286 | /** |
||
287 | * @return Set |
||
288 | */ |
||
289 | 1 | public function getValueAsLocalizedStringSet() |
|
295 | |||
296 | /** |
||
297 | * @return Set |
||
298 | */ |
||
299 | 1 | public function getValueAsLocalizedEnumSet() |
|
305 | |||
306 | /** |
||
307 | * @return Set |
||
308 | */ |
||
309 | 2 | public function getValueAsEnumSet() |
|
315 | |||
316 | /** |
||
317 | * @return Set |
||
318 | */ |
||
319 | 1 | public function getValueAsMoneySet() |
|
325 | |||
326 | /** |
||
327 | * @return Set |
||
328 | */ |
||
329 | public function getValueAsDateSet() |
||
335 | |||
336 | /** |
||
337 | * @return Set |
||
338 | */ |
||
339 | public function getValueAsTimeSet() |
||
345 | |||
346 | /** |
||
347 | * @return Set |
||
348 | */ |
||
349 | public function getValueAsDateTimeSet() |
||
355 | |||
356 | /** |
||
357 | * @return Set |
||
358 | */ |
||
359 | 1 | public function getValueAsNestedSet() |
|
365 | |||
366 | /** |
||
367 | * @return Set |
||
368 | */ |
||
369 | 1 | public function getValueAsReferenceSet() |
|
375 | |||
376 | /** |
||
377 | * @param $value |
||
378 | * @return string |
||
379 | */ |
||
380 | 15 | protected function guessApiType($value) |
|
404 | |||
405 | /** |
||
406 | * @param $value |
||
407 | * @param string[] $keys |
||
408 | * @return bool |
||
409 | */ |
||
410 | 9 | protected function hasKeys($value, $keys) |
|
418 | |||
419 | 15 | protected function guessUnknown($value) |
|
423 | |||
424 | 13 | protected function guessTextLike($value) |
|
428 | |||
429 | 14 | protected function guessBool($value) |
|
433 | |||
434 | 11 | protected function guessNumber($value) |
|
438 | |||
439 | 9 | View Code Duplication | protected function guessEnum($value) |
447 | |||
448 | 8 | View Code Duplication | protected function guessLocalizedEnum($value) |
456 | |||
457 | 7 | View Code Duplication | protected function guessMoney($value) |
465 | |||
466 | 6 | View Code Duplication | protected function guessReference($value) |
474 | |||
475 | 4 | protected function guessLocalizedText($value) |
|
483 | |||
484 | 2 | protected function guessSet($value) |
|
492 | |||
493 | 3 | protected function guessNested($value) |
|
504 | } |
||
505 |
If you implement
__call
and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.This is often the case, when
__call
is implemented by a parent class and only the child class knows which methods exist: