$value) { if (is_numeric($value)) { $stack[] = $value; } else { $a = self::parseValue(array_pop($stack) ?? 0); $b = self::parseValue(array_pop($stack) ?? 0); if ($value === '+') { $stack[] = $a + $b; } elseif ($value === '-') { $stack[] = $b - $a; } elseif ($value === '*') { $stack[] = $a * $b; } elseif ($value === '/') { $stack[] = $b / $a; } elseif ($value === '^') { $stack[] = $b ** $a; } } } $result = array_pop($stack); return is_numeric($result) ? (float) $result : null; } /** * Parse value. * * @param int|float|string $value Value to parse * * @return int|float * * @since 1.0.0 */ private static function parseValue(int | float | string $value) : int | float { return !\is_string($value) ? $value : (stripos($value, '.') === false ? (int) $value : (float) $value); } /** * Shunting Yard algorithm. * * @param string $equation Equation to convert * * @return string[] * * @since 1.0.0 */ private static function shuntingYard(string $equation) : array { $stack = []; $operators = [ '^' => ['precedence' => 4, 'order' => 1], '*' => ['precedence' => 3, 'order' => -1], '/' => ['precedence' => 3, 'order' => -1], '+' => ['precedence' => 2, 'order' => -1], '-' => ['precedence' => 2, 'order' => -1], ]; $output = []; $equation = str_replace(' ', '', $equation); $equation = preg_split('/([\+\-\*\/\^\(\)])/', $equation, -1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); if ($equation === false) { return []; // @codeCoverageIgnore } $equation = array_filter($equation, function($n) { return $n !== ''; }); foreach ($equation as $i => $token) { if (is_numeric($token)) { $output[] = $token; } elseif (strpbrk($token, '^*/+-') !== false) { $o1 = $token; $o2 = end($stack); while ($o2 !== false && strpbrk($o2, '^*/+-') !== false && (($operators[$o1]['order'] === -1 && $operators[$o1]['precedence'] <= $operators[$o2]['precedence']) || ($operators[$o1]['order'] === 1 && $operators[$o1]['precedence'] < $operators[$o2]['precedence'])) ) { $output[] = array_pop($stack); $o2 = end($stack); } $stack[] = $o1; } elseif ($token === '(') { $stack[] = $token; } elseif ($token === ')') { while (end($stack) !== '(') { $output[] = array_pop($stack); } array_pop($stack); } } while (\count($stack) > 0) { $output[] = array_pop($stack); } /** @var string[] $output */ return $output; } }