Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.62% covered (success)
97.62%
41 / 42
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Expression
97.62% covered (success)
97.62%
41 / 42
80.00% covered (warning)
80.00%
4 / 5
18
0.00% covered (danger)
0.00%
0 / 1
 eval
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
6.01
 cleanExpression
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 matchExpressionPattern
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 expression
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 postfixNotationStack
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace Projom\Util\Math;
6
7class 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}