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 Expectations 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 Expectations, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | final class Expectations |
||
10 | { |
||
11 | /** |
||
12 | * @var mixed |
||
13 | */ |
||
14 | private $value; |
||
15 | /** |
||
16 | * @var bool |
||
17 | */ |
||
18 | private $approved = true; |
||
19 | |||
20 | /** |
||
21 | * Expectations constructor. |
||
22 | * |
||
23 | * @param $value |
||
24 | */ |
||
25 | public function __construct($value) |
||
29 | |||
30 | /** |
||
31 | * @return Expectations |
||
32 | */ |
||
33 | private function reject(): self |
||
39 | |||
40 | /** |
||
41 | * @param bool $condition |
||
42 | * |
||
43 | * @return Expectations |
||
44 | */ |
||
45 | private function approveIf(bool $condition): self |
||
51 | |||
52 | /** |
||
53 | * @return bool |
||
54 | */ |
||
55 | public function isApproved(): bool |
||
59 | |||
60 | /** |
||
61 | * @param callable $callback |
||
62 | * |
||
63 | * @return Expectations |
||
64 | */ |
||
65 | public function is(callable $callback): self |
||
69 | |||
70 | /** |
||
71 | * @param callable $callback |
||
72 | * |
||
73 | * @return Expectations |
||
74 | */ |
||
75 | public function isNot(callable $callback): self |
||
79 | |||
80 | /** |
||
81 | * @return Expectations |
||
82 | */ |
||
83 | public function isInt(): self |
||
87 | |||
88 | /** |
||
89 | * @return Expectations |
||
90 | */ |
||
91 | public function isFloat(): self |
||
95 | |||
96 | /** |
||
97 | * @return Expectations |
||
98 | */ |
||
99 | public function isScalar(): self |
||
103 | |||
104 | /** |
||
105 | * @return Expectations |
||
106 | */ |
||
107 | public function isNumeric(): self |
||
111 | |||
112 | /** |
||
113 | * @return Expectations |
||
114 | */ |
||
115 | public function isString(): self |
||
119 | |||
120 | /** |
||
121 | * @return Expectations |
||
122 | */ |
||
123 | public function isBool(): self |
||
127 | |||
128 | /** |
||
129 | * @return Expectations |
||
130 | */ |
||
131 | public function isArray(): self |
||
135 | |||
136 | /** |
||
137 | * @return Expectations |
||
138 | */ |
||
139 | public function isObject(): self |
||
143 | |||
144 | /** |
||
145 | * @param $object |
||
146 | * |
||
147 | * @return Expectations |
||
148 | */ |
||
149 | public function isInstanceOf($object): self |
||
157 | |||
158 | /** |
||
159 | * @return Expectations |
||
160 | */ |
||
161 | public function isCallable(): self |
||
165 | |||
166 | /** |
||
167 | * @return Expectations |
||
168 | */ |
||
169 | public function isDir(): self |
||
173 | |||
174 | /** |
||
175 | * @return Expectations |
||
176 | */ |
||
177 | public function isFile(): self |
||
181 | |||
182 | /** |
||
183 | * @return Expectations |
||
184 | */ |
||
185 | public function isEmpty(): self |
||
189 | |||
190 | /** |
||
191 | * @return Expectations |
||
192 | */ |
||
193 | public function isNotEmpty(): self |
||
197 | |||
198 | /** |
||
199 | * @return Expectations |
||
200 | */ |
||
201 | public function isNull(): self |
||
205 | |||
206 | /** |
||
207 | * @return Expectations |
||
208 | */ |
||
209 | public function isNotNull(): self |
||
213 | |||
214 | /** |
||
215 | * @return Expectations |
||
216 | */ |
||
217 | public function isTrue(): self |
||
221 | |||
222 | /** |
||
223 | * @return Expectations |
||
224 | */ |
||
225 | public function isFalse(): self |
||
229 | |||
230 | /** |
||
231 | * @param $value |
||
232 | * |
||
233 | * @return Expectations |
||
234 | */ |
||
235 | public function isEqual($value): self |
||
239 | |||
240 | /** |
||
241 | * @param $value |
||
242 | * |
||
243 | * @return Expectations |
||
244 | */ |
||
245 | public function isNotEqual($value): self |
||
249 | |||
250 | /** |
||
251 | * @param $value |
||
252 | * |
||
253 | * @return Expectations |
||
254 | */ |
||
255 | public function isIdenticalTo($value): self |
||
259 | |||
260 | /** |
||
261 | * @param $value |
||
262 | * |
||
263 | * @return Expectations |
||
264 | */ |
||
265 | public function isNotIdenticalTo($value): self |
||
269 | |||
270 | /** |
||
271 | * @param int $lhs |
||
272 | * @param int $rhs |
||
273 | * |
||
274 | * @return Expectations |
||
275 | */ |
||
276 | public function isBetween(int $lhs, int $rhs): self |
||
284 | |||
285 | /** |
||
286 | * @param int $length |
||
287 | * |
||
288 | * @return Expectations |
||
289 | */ |
||
290 | public function hasLength(int $length): self |
||
302 | |||
303 | /** |
||
304 | * @param array $values |
||
305 | * |
||
306 | * @return Expectations |
||
307 | */ |
||
308 | public function isIn(array $values): self |
||
312 | |||
313 | /** |
||
314 | * @param array $values |
||
315 | * |
||
316 | * @return Expectations |
||
317 | */ |
||
318 | public function isKeyOf(array $values): self |
||
322 | |||
323 | /** |
||
324 | * @param int $value |
||
325 | * |
||
326 | * @return Expectations |
||
327 | */ |
||
328 | public function isBelow(int $value): self |
||
336 | |||
337 | /** |
||
338 | * @param int $value |
||
339 | * |
||
340 | * @return Expectations |
||
341 | */ |
||
342 | public function isAbove(int $value): self |
||
350 | |||
351 | /** |
||
352 | * @param int $value |
||
353 | * |
||
354 | * @return Expectations |
||
355 | */ |
||
356 | public function isBelowOrEqual(int $value): self |
||
364 | |||
365 | /** |
||
366 | * @param int $value |
||
367 | * |
||
368 | * @return Expectations |
||
369 | */ |
||
370 | public function isAboveOrEqual(int $value): self |
||
378 | |||
379 | /** |
||
380 | * @return Expectations |
||
381 | */ |
||
382 | public function isPositive(): self |
||
386 | |||
387 | /** |
||
388 | * @return Expectations |
||
389 | */ |
||
390 | public function isNegative(): self |
||
394 | |||
395 | /** |
||
396 | * @return Expectations |
||
397 | */ |
||
398 | View Code Duplication | public function isEven(): self |
|
406 | |||
407 | /** |
||
408 | * @return Expectations |
||
409 | */ |
||
410 | View Code Duplication | public function isOdd(): self |
|
418 | |||
419 | /** |
||
420 | * @param string $pattern |
||
421 | * |
||
422 | * @return Expectations |
||
423 | */ |
||
424 | public function match(string $pattern): self |
||
432 | |||
433 | /** |
||
434 | * @param $value |
||
435 | * |
||
436 | * @return mixed |
||
437 | */ |
||
438 | public function then($value) |
||
442 | |||
443 | /** |
||
444 | * @param $default |
||
445 | * |
||
446 | * @return mixed |
||
447 | */ |
||
448 | public function else($default) |
||
452 | } |
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.