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 Project 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 Project, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
29 | class Project |
||
30 | { |
||
31 | /** |
||
32 | * URL to check for updates, if a given project doesn't define its own. |
||
33 | */ |
||
34 | const UPDATE_DEFAULT_URL = 'http://updates.drupal.org/release-history'; |
||
35 | |||
36 | /** |
||
37 | * |
||
38 | */ |
||
39 | const INSTALL_TYPE_OFFICIAL = 'official'; |
||
40 | |||
41 | /** |
||
42 | * |
||
43 | */ |
||
44 | const INSTALL_TYPE_DEV = 'dev'; |
||
45 | |||
46 | /** |
||
47 | * |
||
48 | */ |
||
49 | const INSTALL_TYPE_UNKNOWN = 'unknown'; |
||
50 | |||
51 | /** |
||
52 | * |
||
53 | */ |
||
54 | const TYPE_PROJECT_DISTRIBUTION = 'project_distribution'; |
||
55 | |||
56 | /** |
||
57 | * |
||
58 | */ |
||
59 | const TYPE_PROJECT_CORE = 'project_core'; |
||
60 | |||
61 | /** |
||
62 | * |
||
63 | */ |
||
64 | const TYPE_PROJECT_MODULE = 'project_module'; |
||
65 | |||
66 | /** |
||
67 | * |
||
68 | */ |
||
69 | const TYPE_PROJECT_THEME = 'project_theme'; |
||
70 | |||
71 | /** |
||
72 | * |
||
73 | */ |
||
74 | const TYPE_UNKNOWN = 'unknown'; |
||
75 | |||
76 | /** |
||
77 | * @var |
||
78 | */ |
||
79 | protected $project; |
||
80 | |||
81 | /** |
||
82 | * @var string |
||
83 | */ |
||
84 | protected $filename; |
||
85 | |||
86 | /** |
||
87 | * @var |
||
88 | */ |
||
89 | protected $name; |
||
90 | |||
91 | /** |
||
92 | * @var |
||
93 | */ |
||
94 | protected $core; |
||
95 | |||
96 | /** |
||
97 | * @var |
||
98 | */ |
||
99 | protected $version; |
||
100 | |||
101 | /** |
||
102 | * @var |
||
103 | */ |
||
104 | protected $status_url; |
||
105 | |||
106 | /** |
||
107 | * @var |
||
108 | */ |
||
109 | protected $install_type; |
||
110 | |||
111 | /** |
||
112 | * @var |
||
113 | */ |
||
114 | protected $existing_version; |
||
115 | |||
116 | /** |
||
117 | * @var |
||
118 | */ |
||
119 | protected $existing_major; |
||
120 | |||
121 | /** |
||
122 | * @var array |
||
123 | */ |
||
124 | protected $data; |
||
125 | |||
126 | // Calculated properties. |
||
127 | |||
128 | /** |
||
129 | * @var |
||
130 | */ |
||
131 | protected $status; |
||
132 | |||
133 | /** |
||
134 | * @var |
||
135 | */ |
||
136 | protected $project_status; |
||
137 | |||
138 | /** |
||
139 | * @var string |
||
140 | */ |
||
141 | protected $project_type; |
||
142 | |||
143 | /** |
||
144 | * @var |
||
145 | */ |
||
146 | protected $reason; |
||
147 | |||
148 | /** |
||
149 | * @var |
||
150 | */ |
||
151 | protected $fetch_status; |
||
152 | |||
153 | /** |
||
154 | * @var |
||
155 | */ |
||
156 | protected $latest_version; |
||
157 | |||
158 | /** |
||
159 | * @var |
||
160 | */ |
||
161 | protected $latest_dev; |
||
162 | |||
163 | /** |
||
164 | * @var |
||
165 | */ |
||
166 | protected $dev_version; |
||
167 | |||
168 | /** |
||
169 | * @var |
||
170 | */ |
||
171 | protected $recommended; |
||
172 | |||
173 | /** |
||
174 | * @var |
||
175 | */ |
||
176 | protected $datestamp; |
||
177 | |||
178 | /** |
||
179 | * @var array |
||
180 | */ |
||
181 | protected $releases; |
||
182 | |||
183 | /** |
||
184 | * @var array |
||
185 | */ |
||
186 | protected $security_updates; |
||
187 | |||
188 | /** |
||
189 | * @var array |
||
190 | */ |
||
191 | protected $also_available; |
||
192 | |||
193 | /** |
||
194 | * @param string $project |
||
195 | * @param string $core |
||
196 | * @param string $version |
||
197 | * @param \DateTime|int|null $date |
||
198 | */ |
||
199 | public function __construct($project, $core, $version, $date = null) |
||
220 | |||
221 | /** |
||
222 | * @return string |
||
223 | */ |
||
224 | public function getFilename() |
||
228 | |||
229 | /** |
||
230 | * @param string $filename |
||
231 | */ |
||
232 | public function setFilename($filename) |
||
238 | |||
239 | /** |
||
240 | * @return string |
||
241 | */ |
||
242 | public function getWorkingDirectory() |
||
266 | |||
267 | /** |
||
268 | * |
||
269 | */ |
||
270 | protected function init() |
||
320 | |||
321 | /** |
||
322 | * @param string $version |
||
323 | * @param Release $release |
||
324 | */ |
||
325 | public function addSecurityUpdate($version, $release) |
||
329 | |||
330 | /** |
||
331 | * @param string $version_major |
||
332 | * @param string $version |
||
333 | */ |
||
334 | public function addAlsoAvailable($version_major, $version) |
||
338 | |||
339 | /** |
||
340 | * @return array |
||
341 | */ |
||
342 | public function getAlsoAvailable() |
||
346 | |||
347 | /** |
||
348 | * @param string $version_major |
||
349 | * @return bool |
||
350 | */ |
||
351 | public function hasAlsoAvailable($version_major) |
||
355 | |||
356 | /** |
||
357 | * @return mixed |
||
358 | */ |
||
359 | public function getCore() |
||
363 | |||
364 | /** |
||
365 | * @return mixed |
||
366 | */ |
||
367 | public function getDatestamp() |
||
371 | |||
372 | /** |
||
373 | * @return array |
||
374 | */ |
||
375 | public function getDetails() |
||
379 | |||
380 | /** |
||
381 | * @return string |
||
382 | */ |
||
383 | public function getProjectType() |
||
387 | |||
388 | /** |
||
389 | * @param string $type |
||
390 | */ |
||
391 | public function setProjectType($type) |
||
395 | |||
396 | /** |
||
397 | * @return mixed |
||
398 | */ |
||
399 | public function getDevVersion() |
||
403 | |||
404 | /** |
||
405 | * @param $dev_version |
||
406 | */ |
||
407 | public function setDevVersion($dev_version) |
||
411 | |||
412 | /** |
||
413 | * @return string |
||
414 | */ |
||
415 | public function getExistingMajor() |
||
419 | |||
420 | /** |
||
421 | * @return string |
||
422 | */ |
||
423 | public function getExistingVersion() |
||
427 | |||
428 | /** |
||
429 | * @return integer |
||
430 | */ |
||
431 | public function getFetchStatus() |
||
435 | |||
436 | /** |
||
437 | * @param $fetch_status |
||
438 | */ |
||
439 | public function setFetchStatus($fetch_status) |
||
443 | |||
444 | /** |
||
445 | * @return string |
||
446 | */ |
||
447 | public function getInstallType() |
||
451 | |||
452 | /** |
||
453 | * @return mixed |
||
454 | */ |
||
455 | public function getLatestDev() |
||
459 | |||
460 | /** |
||
461 | * @param $latest_dev |
||
462 | */ |
||
463 | public function setLatestDev($latest_dev) |
||
467 | |||
468 | /** |
||
469 | * @return mixed |
||
470 | */ |
||
471 | public function getLatestVersion() |
||
475 | |||
476 | /** |
||
477 | * @param $latest_version |
||
478 | */ |
||
479 | public function setLatestVersion($latest_version) |
||
483 | |||
484 | /** |
||
485 | * @return string |
||
486 | */ |
||
487 | public function getName() |
||
491 | |||
492 | /** |
||
493 | * @return string |
||
494 | */ |
||
495 | public function getProject() |
||
499 | |||
500 | /** |
||
501 | * @return int |
||
502 | */ |
||
503 | public function getProjectStatus() |
||
507 | |||
508 | /** |
||
509 | * @param int $project_status |
||
510 | */ |
||
511 | public function setProjectStatus($project_status) |
||
515 | |||
516 | /** |
||
517 | * @return string |
||
518 | */ |
||
519 | public function getReason() |
||
523 | |||
524 | /** |
||
525 | * @param string $reason |
||
526 | */ |
||
527 | public function setReason($reason) |
||
531 | |||
532 | /** |
||
533 | * @return mixed |
||
534 | */ |
||
535 | public function getRecommended() |
||
539 | |||
540 | /** |
||
541 | * @param $recommended |
||
542 | */ |
||
543 | public function setRecommended($recommended) |
||
547 | |||
548 | /** |
||
549 | * @return Release[] |
||
550 | */ |
||
551 | public function getReleases() |
||
555 | |||
556 | /** |
||
557 | * @param Release[] $releases |
||
558 | */ |
||
559 | public function setReleases($releases) |
||
563 | |||
564 | /** |
||
565 | * @param string $release |
||
566 | * |
||
567 | * @return Release|false |
||
568 | */ |
||
569 | public function getRelease($release) |
||
577 | |||
578 | /** |
||
579 | * @return Release[] |
||
580 | */ |
||
581 | public function getSecurityUpdates() |
||
585 | |||
586 | /** |
||
587 | * @param Release[] $security_updates |
||
588 | */ |
||
589 | public function setSecurityUpdates($security_updates) |
||
593 | |||
594 | /** |
||
595 | * @return int |
||
596 | */ |
||
597 | public function getStatus() |
||
601 | |||
602 | /** |
||
603 | * @param int $status |
||
604 | */ |
||
605 | public function setStatus($status) |
||
609 | |||
610 | /** |
||
611 | * @return string |
||
612 | */ |
||
613 | public function getStatusUrl() |
||
617 | |||
618 | /** |
||
619 | * @param string $status_url |
||
620 | */ |
||
621 | public function setStatusUrl($status_url) |
||
625 | |||
626 | /** |
||
627 | * @return string |
||
628 | */ |
||
629 | public function getVersion() |
||
633 | |||
634 | /** |
||
635 | * @return bool |
||
636 | */ |
||
637 | public function hasSecurityUpdates() |
||
641 | |||
642 | /** |
||
643 | * @param array $data |
||
644 | */ |
||
645 | public function setDetails($data) |
||
657 | |||
658 | /** |
||
659 | * @param string $version |
||
660 | * @param Release $release |
||
661 | */ |
||
662 | public function setRelease($version, Release $release) |
||
666 | } |
||
667 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.