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:
1 | <?php |
||
9 | class MathEnv implements EnvInterface |
||
10 | { |
||
11 | use MappedEnvTrait; |
||
12 | |||
13 | const INVALID_ARG_REQUIRES_NUMERIC = 'All arguments must be numeric'; |
||
14 | const INVALID_ARG_TYPE_PRED_MATCH = 'Supplied arguments do not match the first'; |
||
15 | |||
16 | const MAPPING = [ |
||
17 | '+' => 'add', |
||
18 | '-' => 'subtract', |
||
19 | '*' => 'multiply', |
||
20 | '/' => 'divide', |
||
21 | '>' => 'isGreaterThan', |
||
22 | '>=' => 'isGreaterThanOrEqual', |
||
23 | '<' => 'isSmallerThan', |
||
24 | '<=' => 'isSmallerThanOrEqual', |
||
25 | '=' => 'isEqual', |
||
26 | 'number?' => 'isNumber', |
||
27 | 'integer?' => 'isInteger', |
||
28 | 'real?' => 'isReal', |
||
29 | 'complex?' => 'isComplex', |
||
30 | 'exact?' => 'isExact', |
||
31 | 'inexact?' => 'isInexact', |
||
32 | 'positive?' => 'isPositive', |
||
33 | 'negative?' => 'isNegative', |
||
34 | 'odd?' => 'isOdd', |
||
35 | 'even?' => 'isEven', |
||
36 | ]; |
||
37 | |||
38 | /** @var float */ |
||
39 | public $pi = M_PI; |
||
40 | |||
41 | /** |
||
42 | * Sum the args |
||
43 | * |
||
44 | * @param int[]|float[] $args |
||
45 | * @return int|float |
||
46 | * @throws \InvalidArgumentException |
||
47 | */ |
||
48 | 1 | public function add(...$args) |
|
53 | |||
54 | /** |
||
55 | * Subtract the args |
||
56 | * |
||
57 | * @param int[]|float[] $args |
||
58 | * @return int|float |
||
59 | * @throws \InvalidArgumentException |
||
60 | */ |
||
61 | 1 | View Code Duplication | public function subtract(...$args) |
70 | |||
71 | /** |
||
72 | * Multiply the args |
||
73 | * |
||
74 | * @param int[]|float[] $args |
||
75 | * @return int|float |
||
76 | * @throws \InvalidArgumentException |
||
77 | */ |
||
78 | 1 | public function multiply(...$args) |
|
83 | |||
84 | /** |
||
85 | * Divide the args |
||
86 | * |
||
87 | * @param int[]|float[] $args |
||
88 | * @return int|float |
||
89 | * @throws \InvalidArgumentException |
||
90 | */ |
||
91 | 1 | View Code Duplication | public function divide(...$args) |
100 | |||
101 | /** |
||
102 | * Returns true if $a is greater than $b, otherwise false |
||
103 | * |
||
104 | * @SuppressWarnings(PHPMD.ShortVariable) |
||
105 | * @param int|float $a |
||
106 | * @param int|float $b |
||
107 | * @return bool |
||
108 | */ |
||
109 | 1 | public function isGreaterThan($a, $b): bool |
|
114 | |||
115 | /** |
||
116 | * Returns true if $a is greater than or equal to $b, otherwise false |
||
117 | * |
||
118 | * @SuppressWarnings(PHPMD.ShortVariable) |
||
119 | * @param int|float $a |
||
120 | * @param int|float $b |
||
121 | * @return bool |
||
122 | */ |
||
123 | 1 | public function isGreaterThanOrEqual($a, $b): bool |
|
128 | |||
129 | /** |
||
130 | * Returns true if $a is smaller than or equal to $b, otherwise false |
||
131 | * |
||
132 | * @SuppressWarnings(PHPMD.ShortVariable) |
||
133 | * @param int|float $a |
||
134 | * @param int|float $b |
||
135 | * @return bool |
||
136 | */ |
||
137 | 1 | public function isSmallerThanOrEqual($a, $b): bool |
|
142 | |||
143 | /** |
||
144 | * Returns true if $a is smaller than $b, otherwise false |
||
145 | * |
||
146 | * @SuppressWarnings(PHPMD.ShortVariable) |
||
147 | * @param int|float $a |
||
148 | * @param int|float $b |
||
149 | * @return bool |
||
150 | */ |
||
151 | 1 | public function isSmallerThan($a, $b): bool |
|
156 | |||
157 | /** |
||
158 | * @param int[]|float[] ...$args |
||
159 | * @return bool |
||
160 | * @throws \InvalidArgumentException |
||
161 | */ |
||
162 | 1 | public function isEqual(...$args): bool |
|
177 | |||
178 | /** |
||
179 | * @param mixed $num |
||
180 | * @return bool |
||
181 | */ |
||
182 | 21 | public function isNumber($num): bool |
|
186 | |||
187 | /** |
||
188 | * Scheme's rules for integerness are slightly different than PHP's: |
||
189 | * An integer can be a "float" but it must have `.0` |
||
190 | * |
||
191 | * @param mixed $num |
||
192 | * @return bool |
||
193 | */ |
||
194 | 1 | public function isInteger($num): bool |
|
198 | |||
199 | /** |
||
200 | * Not implemented yet. |
||
201 | * Requires complex number support |
||
202 | * |
||
203 | * @param $num |
||
204 | * @return bool |
||
205 | * @throws \Error |
||
206 | * @SuppressWarnings(PHPMD) |
||
207 | */ |
||
208 | 1 | public function isComplex($num): bool |
|
212 | |||
213 | /** |
||
214 | * Not implemented yet. |
||
215 | * Requires complex number support |
||
216 | * |
||
217 | * @param $num |
||
218 | * @return bool |
||
219 | * @throws \Error |
||
220 | * @SuppressWarnings(PHPMD) |
||
221 | */ |
||
222 | 1 | public function isReal($num): bool |
|
226 | |||
227 | /** |
||
228 | * @param $num |
||
229 | * @return bool |
||
230 | * @throws \InvalidArgumentException |
||
231 | */ |
||
232 | 2 | public function isExact($num): bool |
|
238 | |||
239 | /** |
||
240 | * @param $num |
||
241 | * @return bool |
||
242 | * @throws \InvalidArgumentException |
||
243 | */ |
||
244 | 1 | public function isInexact($num): bool |
|
248 | |||
249 | /** |
||
250 | * @param $num |
||
251 | * @return bool |
||
252 | * @throws \InvalidArgumentException |
||
253 | */ |
||
254 | 1 | public function isZero($num): bool |
|
260 | |||
261 | /** |
||
262 | * @param $num |
||
263 | * @return bool |
||
264 | * @throws \InvalidArgumentException |
||
265 | */ |
||
266 | 2 | public function isPositive($num): bool |
|
272 | |||
273 | /** |
||
274 | * @param $num |
||
275 | * @return bool |
||
276 | * @throws \InvalidArgumentException |
||
277 | */ |
||
278 | 1 | public function isNegative($num): bool |
|
282 | |||
283 | /** |
||
284 | * @param $num |
||
285 | * @return bool |
||
286 | * @throws \InvalidArgumentException |
||
287 | */ |
||
288 | 2 | public function isOdd($num): bool |
|
294 | |||
295 | /** |
||
296 | * @param $num |
||
297 | * @return bool |
||
298 | * @throws \InvalidArgumentException |
||
299 | */ |
||
300 | 1 | public function isEven($num): bool |
|
304 | |||
305 | /** |
||
306 | * @param int[]|float[] ...$args |
||
307 | * @return int|float |
||
308 | * @throws \InvalidArgumentException |
||
309 | */ |
||
310 | 1 | public function max(...$args) |
|
316 | |||
317 | /** |
||
318 | * @param int[]|float[] ...$args |
||
319 | * @return int|float |
||
320 | * @throws \InvalidArgumentException |
||
321 | */ |
||
322 | 1 | public function min(...$args) |
|
328 | |||
329 | /** |
||
330 | * @param int|float $arg |
||
331 | * @return int|float |
||
332 | */ |
||
333 | 1 | public function abs($arg) |
|
339 | |||
340 | /** |
||
341 | * Used as the callback to array_reduce, with the "carry" argument being the predicate to enforce |
||
342 | * |
||
343 | * @param callable $pred |
||
344 | * @param $thingToCheck |
||
345 | * @return callable |
||
346 | * @throws \InvalidArgumentException |
||
347 | * @SuppressWarnings(PHPMD.UnusedPrivateMethod) |
||
348 | */ |
||
349 | 19 | private function enforcePredicate(callable $pred, $thingToCheck): callable |
|
357 | } |
||
358 |
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.