aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier Marín <javier@marinros.com>2020-07-26 05:27:26 +0300
committerGitHub <noreply@github.com>2020-07-26 05:27:26 +0300
commitc1e07f254a4e952868be8240080661628aef8e69 (patch)
treeb7ff2fa4c478a9ccc2fd0d17c64d54732f3391fb
parentaa8ffe19f2eb6f194b3e6ee1aac4c2706659e6b9 (diff)
Handler for not found variables (#68)
* Added handler to define not found variables Added support for string variables Fixed strings and ints comparison error * Check if variables have scalar types (int, float, string and bool) Better $onVarNotFound logic
-rw-r--r--src/NXP/Classes/Calculator.php14
-rw-r--r--src/NXP/Exception/MathExecutorException.php2
-rw-r--r--src/NXP/MathExecutor.php48
-rw-r--r--tests/MathTest.php31
4 files changed, 81 insertions, 14 deletions
diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php
index bcb4b4e..49142df 100644
--- a/src/NXP/Classes/Calculator.php
+++ b/src/NXP/Classes/Calculator.php
@@ -49,7 +49,7 @@ class Calculator
* @throws IncorrectExpressionException
* @throws UnknownVariableException
*/
- public function calculate(array $tokens, array $variables)
+ public function calculate(array $tokens, array $variables, callable $onVarNotFound = null)
{
/** @var Token[] $stack */
$stack = [];
@@ -58,10 +58,18 @@ class Calculator
$stack[] = $token;
} elseif ($token->type === Token::Variable) {
$variable = $token->value;
- if (!array_key_exists($variable, $variables)) {
+
+ $value = null;
+ if (array_key_exists($variable, $variables)) {
+ $value = $variables[$variable];
+ } elseif ($onVarNotFound) {
+ $value = call_user_func($onVarNotFound, $variable);
+ }
+
+ if (!isset($value)) {
throw new UnknownVariableException($variable);
}
- $value = $variables[$variable];
+
$stack[] = new Token(Token::Literal, $value);
} elseif ($token->type === Token::Function) {
if (!array_key_exists($token->value, $this->functions)) {
diff --git a/src/NXP/Exception/MathExecutorException.php b/src/NXP/Exception/MathExecutorException.php
index 0e3ea84..4405f85 100644
--- a/src/NXP/Exception/MathExecutorException.php
+++ b/src/NXP/Exception/MathExecutorException.php
@@ -14,6 +14,6 @@ namespace NXP\Exception;
/**
* @author Vitaliy Zhuk <zhuk2205@gmail.com>
*/
-abstract class MathExecutorException extends \Exception
+class MathExecutorException extends \Exception
{
}
diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php
index 8f876dc..d23ba80 100644
--- a/src/NXP/MathExecutor.php
+++ b/src/NXP/MathExecutor.php
@@ -15,9 +15,9 @@ use NXP\Classes\Calculator;
use NXP\Classes\CustomFunction;
use NXP\Classes\Operator;
use NXP\Classes\Tokenizer;
-use NXP\Exception\MathExecutorException;
use NXP\Exception\DivisionByZeroException;
use NXP\Exception\UnknownVariableException;
+use NXP\Exception\MathExecutorException;
use ReflectionException;
/**
@@ -34,6 +34,11 @@ class MathExecutor
private $variables = [];
/**
+ * @var callable
+ */
+ private $onVarNotFound = null;
+
+ /**
* @var Operator[]
*/
private $operators = [];
@@ -134,14 +139,22 @@ class MathExecutor
],
'==' => [
function ($a, $b) {
- return $a == $b;
+ if (is_string($a) || is_string($b)) {
+ return strcmp($a, $b) == 0;
+ } else {
+ return $a == $b;
+ }
},
140,
false
],
'!=' => [
function ($a, $b) {
- return $a != $b;
+ if (is_string($a) || is_string($b)) {
+ return strcmp($a, $b) != 0;
+ } else {
+ return $a != $b;
+ }
},
140,
false
@@ -353,7 +366,7 @@ class MathExecutor
$tokens = $this->cache[$cachekey];
}
$calculator = new Calculator($this->functions, $this->operators);
- return $calculator->calculate($tokens, $this->variables);
+ return $calculator->calculate($tokens, $this->variables, $this->onVarNotFound);
}
/**
@@ -415,13 +428,13 @@ class MathExecutor
* @param string $variable
* @param integer|float $value
* @return MathExecutor
- * @throws MathExecutorException
*/
public function setVar(string $variable, $value) : self
{
- if (!is_numeric($value)) {
- throw new MathExecutorException("Variable ({$variable}) value must be a number ({$value}) type ({gettype($value)})");
+ if (!is_scalar($value)) {
+ throw new MathExecutorException("Variable ({$variable}) value must be a scalar type ({gettype($value)})");
}
+
$this->variables[$variable] = $value;
return $this;
}
@@ -446,6 +459,20 @@ class MathExecutor
}
/**
+ * Define a method that will be invoked when a variable is not found.
+ * The first parameter will be the variable name, and the returned value will be used as the variable value.
+ *
+ * @param callable $handler
+ *
+ * @return MathExecutor
+ */
+ public function setVarNotFoundHandler(callable $handler): self
+ {
+ $this->onVarNotFound = $handler;
+ return $this;
+ }
+
+ /**
* Remove variable from executor
*
* @param string $variable
@@ -458,12 +485,13 @@ class MathExecutor
}
/**
- * Remove all variables
+ * Remove all variables and the variable not found handler
* @return MathExecutor
*/
public function removeVars() : self
{
$this->variables = [];
+ $this->onVarNotFound = null;
return $this;
}
@@ -474,7 +502,7 @@ class MathExecutor
*/
public function getOperators()
{
- return $this->tokenFactory->getOperators();
+ return $this->operators;
}
/**
@@ -485,7 +513,7 @@ class MathExecutor
*/
public function getFunctions() : array
{
- return $this->tokenFactory->getFunctions();
+ return $this->functions;
}
/**
diff --git a/tests/MathTest.php b/tests/MathTest.php
index ee9c6bd..d76a57c 100644
--- a/tests/MathTest.php
+++ b/tests/MathTest.php
@@ -409,6 +409,37 @@ class MathTest extends TestCase
$this->assertEquals(1, $calculator->execute('(-4 + 5)'));
}
+ public function testStringComparison()
+ {
+ $calculator = new MathExecutor();
+ $this->assertEquals(true, $calculator->execute('"a" == \'a\''));
+ $this->assertEquals(true, $calculator->execute('"hello world" == "hello world"'));
+ $this->assertEquals(false, $calculator->execute('"hello world" == "hola mundo"'));
+ $this->assertEquals(true, $calculator->execute('"hello world" != "hola mundo"'));
+ }
+
+ public function testVarStringComparison()
+ {
+ $calculator = new MathExecutor();
+ $calculator->setVar('var', 0);
+ $this->assertEquals($calculator->execute('0 == "a"'), $calculator->execute('var == "a"'));
+ }
+
+ public function testOnVarNotFound()
+ {
+ $calculator = new MathExecutor();
+ $calculator->setVarNotFoundHandler(
+ function ($varName) {
+ if ($varName == 'undefined') {
+ return 3;
+ } else {
+ return null;
+ }
+ }
+ );
+ $this->assertEquals(15, $calculator->execute('5 * undefined'));
+ }
+
public function testMinusZero()
{
$calculator = new MathExecutor();