These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | |||
4 | namespace Sphpeme\Env; |
||
5 | |||
6 | /** |
||
7 | * @SuppressWarnings(PHPMD.ShortVariableName) |
||
8 | */ |
||
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) |
|
49 | { |
||
50 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
51 | 1 | return array_sum($args); |
|
52 | } |
||
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) |
62 | { |
||
63 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
64 | |||
65 | 1 | $arg = $args[0]; |
|
66 | 1 | $args = \array_slice($args, 1); |
|
67 | |||
68 | 1 | return $arg - array_sum($args); |
|
69 | } |
||
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) |
|
79 | { |
||
80 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
81 | 1 | return array_product($args); |
|
82 | } |
||
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) |
92 | { |
||
93 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
94 | |||
95 | 1 | $arg = $args[0]; |
|
96 | 1 | $args = \array_slice($args, 1); |
|
97 | |||
98 | 1 | return $arg / array_product($args); |
|
99 | } |
||
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 |
|
110 | { |
||
111 | 1 | array_reduce([$a, $b], [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
112 | 1 | return $a > $b; |
|
113 | } |
||
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 |
|
124 | { |
||
125 | 1 | array_reduce([$a, $b], [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
126 | 1 | return $a >= $b; |
|
127 | } |
||
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 |
|
138 | { |
||
139 | 1 | array_reduce([$a, $b], [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
140 | 1 | return $a <= $b; |
|
141 | } |
||
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 |
|
152 | { |
||
153 | 1 | array_reduce([$a, $b], [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
154 | 1 | return $a < $b; |
|
155 | } |
||
156 | |||
157 | /** |
||
158 | * @param int[]|float[] ...$args |
||
159 | * @return bool |
||
160 | * @throws \InvalidArgumentException |
||
161 | */ |
||
162 | 1 | public function isEqual(...$args): bool |
|
163 | { |
||
164 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
165 | |||
166 | 1 | $arg = $args[0]; |
|
167 | 1 | $args = \array_slice($args, 1); |
|
168 | |||
169 | 1 | foreach ($args as $other) { |
|
170 | 1 | if ($arg != $other) { |
|
171 | 1 | return false; |
|
172 | } |
||
173 | } |
||
174 | |||
175 | 1 | return true; |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * @param mixed $num |
||
180 | * @return bool |
||
181 | */ |
||
182 | 21 | public function isNumber($num): bool |
|
183 | { |
||
184 | 21 | return !\is_string($num) && is_numeric($num); |
|
185 | } |
||
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 |
|
195 | { |
||
196 | 1 | return \is_int($num) ?: $this->isNumber($num) && $num == (int)$num; |
|
197 | } |
||
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 | 2 | public function isComplex($num): bool |
|
209 | { |
||
210 | 2 | throw new \Error('Not implemented'); |
|
211 | return false; |
||
0 ignored issues
–
show
|
|||
212 | } |
||
213 | |||
214 | /** |
||
215 | * Not implemented yet. |
||
216 | * Requires complex number support |
||
217 | * |
||
218 | * @param $num |
||
219 | * @return bool |
||
220 | * @throws \Error |
||
221 | * @SuppressWarnings(PHPMD) |
||
222 | */ |
||
223 | public function isReal($num): bool |
||
224 | { |
||
225 | throw new \Error('Not implemented'); |
||
226 | return false; |
||
0 ignored issues
–
show
return false; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
227 | } |
||
228 | |||
229 | /** |
||
230 | * @param $num |
||
231 | * @return bool |
||
232 | * @throws \InvalidArgumentException |
||
233 | */ |
||
234 | 2 | public function isExact($num): bool |
|
235 | { |
||
236 | 2 | $this->enforcePredicate([$this, 'isNumber'], $num); |
|
237 | |||
238 | 2 | return !\is_float($num); |
|
239 | } |
||
240 | |||
241 | /** |
||
242 | * @param $num |
||
243 | * @return bool |
||
244 | * @throws \InvalidArgumentException |
||
245 | */ |
||
246 | 1 | public function isInexact($num): bool |
|
247 | { |
||
248 | 1 | return !$this->isExact($num); |
|
249 | } |
||
250 | |||
251 | /** |
||
252 | * @param $num |
||
253 | * @return bool |
||
254 | * @throws \InvalidArgumentException |
||
255 | */ |
||
256 | 1 | public function isZero($num): bool |
|
257 | { |
||
258 | 1 | $this->enforcePredicate([$this, 'isNumber'], $num); |
|
259 | |||
260 | 1 | return $num == 0; |
|
261 | } |
||
262 | |||
263 | /** |
||
264 | * @param $num |
||
265 | * @return bool |
||
266 | * @throws \InvalidArgumentException |
||
267 | */ |
||
268 | 2 | public function isPositive($num): bool |
|
269 | { |
||
270 | 2 | $this->enforcePredicate([$this, 'isNumber'], $num); |
|
271 | |||
272 | 2 | return $num > 0; |
|
273 | } |
||
274 | |||
275 | /** |
||
276 | * @param $num |
||
277 | * @return bool |
||
278 | * @throws \InvalidArgumentException |
||
279 | */ |
||
280 | 1 | public function isNegative($num): bool |
|
281 | { |
||
282 | 1 | return !$this->isPositive($num); |
|
283 | } |
||
284 | |||
285 | /** |
||
286 | * @param $num |
||
287 | * @return bool |
||
288 | * @throws \InvalidArgumentException |
||
289 | */ |
||
290 | 2 | public function isOdd($num): bool |
|
291 | { |
||
292 | 2 | $this->enforcePredicate([$this, 'isNumber'], $num); |
|
293 | |||
294 | 2 | return $num % 2 != 0; |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * @param $num |
||
299 | * @return bool |
||
300 | * @throws \InvalidArgumentException |
||
301 | */ |
||
302 | 1 | public function isEven($num): bool |
|
303 | { |
||
304 | 1 | return !$this->isOdd($num); |
|
305 | } |
||
306 | |||
307 | /** |
||
308 | * @param int[]|float[] ...$args |
||
309 | * @return int|float |
||
310 | * @throws \InvalidArgumentException |
||
311 | */ |
||
312 | 1 | public function max(...$args) |
|
313 | { |
||
314 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
315 | |||
316 | 1 | return max(...$args); |
|
317 | } |
||
318 | |||
319 | /** |
||
320 | * @param int[]|float[] ...$args |
||
321 | * @return int|float |
||
322 | * @throws \InvalidArgumentException |
||
323 | */ |
||
324 | 1 | public function min(...$args) |
|
325 | { |
||
326 | 1 | array_reduce($args, [$this, 'enforcePredicate'], [$this, 'isNumber']); |
|
327 | |||
328 | 1 | return min(...$args); |
|
329 | } |
||
330 | |||
331 | /** |
||
332 | * @param int|float $arg |
||
333 | * @return int|float |
||
334 | */ |
||
335 | 1 | public function abs($arg) |
|
336 | { |
||
337 | 1 | $this->enforcePredicate([$this, 'isNumber'], $arg); |
|
338 | |||
339 | 1 | return abs($arg); |
|
340 | } |
||
341 | |||
342 | /** |
||
343 | * Used as the callback to array_reduce, with the "carry" argument being the predicate to enforce |
||
344 | * |
||
345 | * @param callable $pred |
||
346 | * @param $thingToCheck |
||
347 | * @return callable |
||
348 | * @throws \InvalidArgumentException |
||
349 | * @SuppressWarnings(PHPMD.UnusedPrivateMethod) |
||
350 | */ |
||
351 | 19 | private function enforcePredicate(callable $pred, $thingToCheck): callable |
|
352 | { |
||
353 | 19 | if (!$pred($thingToCheck)) { |
|
354 | 16 | throw new \InvalidArgumentException(static::INVALID_ARG_REQUIRES_NUMERIC); |
|
355 | } |
||
356 | |||
357 | 19 | return $pred; |
|
358 | } |
||
359 | } |
||
360 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.