*/ class Calculator { private array $functions = []; private array $operators = []; public function __construct(array $functions, array $operators) { $this->functions = $functions; $this->operators = $operators; } /** * Calculate array of tokens in reverse polish notation * @param Token[] $tokens * @param array $variables * @throws IncorrectExpressionException * @throws UnknownVariableException */ public function calculate(array $tokens, array $variables, ?callable $onVarNotFound = null) { /** @var Token[] $stack */ $stack = []; foreach ($tokens as $token) { if (Token::Literal === $token->type || Token::String === $token->type) { $stack[] = $token; } elseif (Token::Variable === $token->type) { $variable = $token->value; $value = null; if (\array_key_exists($variable, $variables)) { $value = $variables[$variable]; } elseif ($onVarNotFound) { $value = \call_user_func($onVarNotFound, $variable); } else { throw new UnknownVariableException($variable); } $stack[] = new Token(Token::Literal, $value, $variable); } elseif (Token::Function === $token->type) { if (! \array_key_exists($token->value, $this->functions)) { throw new UnknownFunctionException($token->value); } $stack[] = $this->functions[$token->value]->execute($stack); } elseif (Token::Operator === $token->type) { if (! \array_key_exists($token->value, $this->operators)) { throw new UnknownOperatorException($token->value); } $stack[] = $this->operators[$token->value]->execute($stack); } } $result = \array_pop($stack); if (null === $result || ! empty($stack)) { throw new IncorrectExpressionException('Stack must be empty'); } return $result->value; } }