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 PatchService 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 PatchService, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class PatchService implements MoufValidatorInterface { |
||
33 | const IFEXISTS_EXCEPTION = "exception"; |
||
34 | const IFEXISTS_IGNORE = "ignore"; |
||
35 | |||
36 | |||
37 | /** |
||
38 | * The list of patches declared for this application. |
||
39 | * |
||
40 | * @var PatchInterface[] |
||
41 | */ |
||
42 | private $patchs = []; |
||
43 | |||
44 | /** |
||
45 | * The list of exiting patch types for this application. |
||
46 | * |
||
47 | * @var PatchType[] |
||
48 | */ |
||
49 | private $types = []; |
||
50 | |||
51 | /** |
||
52 | * The list of listeners on the patch service. |
||
53 | * |
||
54 | * @var array|PatchListenerInterface[] |
||
55 | */ |
||
56 | private $listeners; |
||
57 | |||
58 | /** |
||
59 | * @param PatchType[] $types |
||
60 | * @param PatchListenerInterface[] $listeners |
||
61 | */ |
||
62 | public function __construct(array $types, array $listeners = []) |
||
67 | |||
68 | /** |
||
69 | * The list of patches declared for this application. |
||
70 | * @param PatchInterface[] $patchs |
||
71 | * @return PatchService |
||
72 | */ |
||
73 | public function setPatchs(array $patchs) { |
||
77 | |||
78 | /** |
||
79 | * The list of exiting patch types for this application. |
||
80 | * |
||
81 | * @return PatchType[] |
||
82 | */ |
||
83 | public function getTypes(): array |
||
87 | |||
88 | /** |
||
89 | * @internal Returns a serialized list of types for the patch UI. |
||
90 | * @return array |
||
91 | */ |
||
92 | public function _getSerializedTypes(): array |
||
98 | |||
99 | /** |
||
100 | * Adds this patch to the list of existing patches. |
||
101 | * If the patch already exists, an exception is thrown. |
||
102 | * Patches are identified by their unique name. |
||
103 | * |
||
104 | * |
||
105 | * @param PatchInterface $patch |
||
106 | * @param string $ifExists |
||
107 | * @throws PatchException |
||
108 | * @return \Mouf\Utils\Patcher\PatchService |
||
109 | */ |
||
110 | public function register(PatchInterface $patch, $ifExists = self::IFEXISTS_IGNORE) { |
||
121 | |||
122 | /** |
||
123 | * Returns true if the patch whose name is $uniqueName is declared in this service. |
||
124 | * @param string $uniqueName |
||
125 | * @return boolean |
||
126 | */ |
||
127 | public function has($uniqueName) { |
||
135 | |||
136 | /** |
||
137 | * Returns the patch whose name is $uniqueName. |
||
138 | * Throws an exception if the patch does not exists. |
||
139 | * @param string $uniqueName |
||
140 | * @return PatchInterface |
||
141 | */ |
||
142 | public function get($uniqueName) { |
||
150 | |||
151 | /** |
||
152 | * Returns the number of patches that needs to be applied. |
||
153 | * |
||
154 | * @return int |
||
155 | */ |
||
156 | View Code Duplication | public function getNbAwaitingPatchs(): int { |
|
165 | |||
166 | /** |
||
167 | * Returns the number of patches that have errors. |
||
168 | * |
||
169 | * @return int |
||
170 | */ |
||
171 | View Code Duplication | public function getNbPatchsInError(): int { |
|
180 | |||
181 | /** |
||
182 | * (non-PHPdoc) |
||
183 | * @see \Mouf\Validator\MoufValidatorInterface::validateInstance() |
||
184 | */ |
||
185 | public function validateInstance() { |
||
223 | |||
224 | /** |
||
225 | * Returns a PHP array representing the patchs. |
||
226 | * |
||
227 | * @internal |
||
228 | */ |
||
229 | public function getView(): array { |
||
267 | |||
268 | /** |
||
269 | * Applies the patch whose unique name is passed in parameter. |
||
270 | * @param string $uniqueName |
||
271 | */ |
||
272 | public function apply($uniqueName): void { |
||
276 | |||
277 | /** |
||
278 | * Skips the patch whose unique name is passed in parameter. |
||
279 | * @param string $uniqueName |
||
280 | */ |
||
281 | public function skip($uniqueName): void { |
||
285 | |||
286 | |||
287 | /** |
||
288 | * Reverts the patch whose unique name is passed in parameter. |
||
289 | * @param string $uniqueName |
||
290 | */ |
||
291 | public function revert($uniqueName): void { |
||
295 | |||
296 | /** |
||
297 | * Apply all remaining patches (patches in state "awaiting" or in "error"). |
||
298 | * The types of the patches can be passed as an array of string where the string is the name of the patch. |
||
299 | * Patches with the "default" type are always applied. |
||
300 | * |
||
301 | * @param string[] $types |
||
302 | * @return array An array containing 2 keys: "applied" and "skipped". Each key contains an associative array with the type of the patch and the number of patches of this type applied. |
||
303 | */ |
||
304 | public function applyAll(array $types = []): array { |
||
333 | |||
334 | /** |
||
335 | * Reset all patches to a not applied state. |
||
336 | * |
||
337 | * Note: this does NOT run the "revert" method on each patch but DOES trigger a "reset" event. |
||
338 | */ |
||
339 | public function reset(): void { |
||
344 | } |
||
345 |
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.