Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
97.62% |
41 / 42 |
|
80.00% |
4 / 5 |
CRAP | |
0.00% |
0 / 1 |
| Expression | |
97.62% |
41 / 42 |
|
80.00% |
4 / 5 |
18 | |
0.00% |
0 / 1 |
| eval | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
6.01 | |||
| cleanExpression | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| matchExpressionPattern | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| expression | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
5 | |||
| postfixNotationStack | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
5 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Projom\Util\Math; |
| 6 | |
| 7 | class Expression |
| 8 | { |
| 9 | const OPERATORS = ['+', '-', '*', '/']; |
| 10 | const PATTERN = '/\d+|\+|\*|-|\/|\(|\)/'; |
| 11 | |
| 12 | public static function eval(string $expression): ?int |
| 13 | { |
| 14 | if (!$expression = static::cleanExpression($expression)) |
| 15 | return null; |
| 16 | |
| 17 | if (!$list = static::matchExpressionPattern($expression)) |
| 18 | return null; |
| 19 | |
| 20 | $stack = []; |
| 21 | $postfixNotationStack = static::postfixNotationStack($list); |
| 22 | foreach ($postfixNotationStack as $item) { |
| 23 | |
| 24 | switch (is_numeric($item)) { |
| 25 | |
| 26 | case true: |
| 27 | $stack[] = $item; |
| 28 | break; |
| 29 | |
| 30 | case false: |
| 31 | $operand_1 = array_shift($stack); |
| 32 | $operator = $item; |
| 33 | $operand_2 = array_shift($stack); |
| 34 | |
| 35 | $result = static::expression($operand_1, $operator, $operand_2); |
| 36 | |
| 37 | $stack[] = $result; |
| 38 | break; |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | return array_shift($stack); |
| 43 | } |
| 44 | |
| 45 | public static function cleanExpression(string $expression): string |
| 46 | { |
| 47 | $expression = trim($expression); |
| 48 | $expression = str_replace(' ', '', $expression); |
| 49 | return $expression; |
| 50 | } |
| 51 | |
| 52 | public static function matchExpressionPattern(string $expression): array |
| 53 | { |
| 54 | preg_match_all(static::PATTERN, $expression, $matches); |
| 55 | $list = $matches[0] ?? []; |
| 56 | return $list; |
| 57 | } |
| 58 | |
| 59 | public static function expression(string|int|float $operand_1, string|int|float $operator, string|int|float $operand_2): string|int|float |
| 60 | { |
| 61 | return match ($operator) { |
| 62 | '+' => $operand_1 + $operand_2, |
| 63 | '-' => $operand_1 - $operand_2, |
| 64 | '*' => $operand_1 * $operand_2, |
| 65 | '/' => $operand_1 / $operand_2, |
| 66 | }; |
| 67 | } |
| 68 | |
| 69 | public static function postfixNotationStack(array $list): array |
| 70 | { |
| 71 | $stack = []; |
| 72 | $operator = ''; |
| 73 | foreach ($list as $item) { |
| 74 | |
| 75 | if (is_numeric($item)) { |
| 76 | |
| 77 | $stack[] = $item; |
| 78 | if ($operator !== '') { |
| 79 | $stack[] = $operator; |
| 80 | $operator = ''; |
| 81 | } |
| 82 | |
| 83 | continue; |
| 84 | } |
| 85 | |
| 86 | if (in_array($item, static::OPERATORS)) |
| 87 | $operator = $item; |
| 88 | } |
| 89 | |
| 90 | return $stack; |
| 91 | } |
| 92 | } |