mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-23 02:28:44 +02:00
Evaluator fixes/enhancements + tests
This commit is contained in:
@@ -3,10 +3,6 @@
|
||||
namespace PhpParser;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar;
|
||||
@@ -37,13 +33,13 @@ class ConstExprEvaluator {
|
||||
/** @var callable|null */
|
||||
private $fallbackEvaluator;
|
||||
|
||||
/** @var array $functions_whitelist */
|
||||
private $functions_whitelist;
|
||||
/** @var array $functionsWhiteList */
|
||||
private $functionsWhiteList;
|
||||
|
||||
/** @var array staticcalls_whitelist */
|
||||
private $staticcalls_whitelist;
|
||||
/** @var array $staticCallsWhitelist */
|
||||
private $staticCallsWhitelist;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Create a constant expression evaluator.
|
||||
*
|
||||
* The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See
|
||||
@@ -58,19 +54,19 @@ class ConstExprEvaluator {
|
||||
);
|
||||
};
|
||||
|
||||
$this->functions_whitelist=[];
|
||||
$this->staticcalls_whitelist=[];
|
||||
$this->functionsWhiteList = [];
|
||||
$this->staticCallsWhitelist = [];
|
||||
}
|
||||
|
||||
public function setFunctionsWhitelist(array $functions_whitelist): void
|
||||
public function setFunctionsWhitelist(array $functionsWhiteList): void
|
||||
{
|
||||
$this->functions_whitelist = $functions_whitelist;
|
||||
$this->functionsWhiteList = $functionsWhiteList;
|
||||
}
|
||||
|
||||
public function setStaticcallsWhitelist(array $staticcalls_whitelist): void
|
||||
public function setStaticCallsWhitelist(array $staticCallsWhitelist): void
|
||||
{
|
||||
$this->staticcalls_whitelist = $staticcalls_whitelist;
|
||||
}
|
||||
$this->staticCallsWhitelist = $staticCallsWhitelist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Silently evaluates a constant expression into a PHP value.
|
||||
@@ -141,6 +137,10 @@ class ConstExprEvaluator {
|
||||
return $this->evaluateArray($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Variable) {
|
||||
return $this->evaluateVariable($expr);
|
||||
}
|
||||
|
||||
// Unary operators
|
||||
if ($expr instanceof Expr\UnaryPlus) {
|
||||
return +$this->evaluate($expr->expr);
|
||||
@@ -191,10 +191,6 @@ class ConstExprEvaluator {
|
||||
return $this->evaluateFuncCall($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Variable) {
|
||||
return $this->evaluateVariable($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\StaticCall) {
|
||||
return $this->evaluateStaticCall($expr);
|
||||
}
|
||||
@@ -236,12 +232,14 @@ class ConstExprEvaluator {
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateBinaryOp(Expr\BinaryOp $expr) {
|
||||
if ($expr instanceof Expr\BinaryOp\Coalesce
|
||||
&& $expr->left instanceof Expr\ArrayDimFetch
|
||||
) {
|
||||
// This needs to be special cased to respect BP_VAR_IS fetch semantics
|
||||
return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]
|
||||
?? $this->evaluate($expr->right);
|
||||
if ($expr instanceof Expr\BinaryOp\Coalesce) {
|
||||
try {
|
||||
$var = $this->evaluate($expr->left);
|
||||
return $var ?? $this->evaluate($expr->right);
|
||||
} catch(\Throwable $t){
|
||||
//handle when isset($expr->left->var)===false
|
||||
return $this->evaluate($expr->right);
|
||||
}
|
||||
}
|
||||
|
||||
// The evaluate() calls are repeated in each branch, because some of the operators are
|
||||
@@ -291,7 +289,7 @@ class ConstExprEvaluator {
|
||||
if(! is_string($name)){
|
||||
//PHP_VERSION_ID usecase
|
||||
$name = $name->name;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($name)){
|
||||
return constant($name);
|
||||
@@ -314,7 +312,7 @@ class ConstExprEvaluator {
|
||||
return true;
|
||||
} catch(\Throwable $t){
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
@@ -410,13 +408,14 @@ class ConstExprEvaluator {
|
||||
private function evaluateFuncCall(Expr\FuncCall $expr)
|
||||
{
|
||||
try {
|
||||
if ($expr->name instanceof Name){
|
||||
$function = $expr->name->name;
|
||||
$name = $expr->name;
|
||||
if ($name instanceof Name){
|
||||
$function = $name->name;
|
||||
} else {
|
||||
$function = $this->evaluate($expr->name);
|
||||
$function = $this->evaluate($name);
|
||||
}
|
||||
|
||||
if (! in_array($function, $this->functions_whitelist)){
|
||||
if (! in_array($function, $this->functionsWhiteList)){
|
||||
throw new Exception("FuncCall $function not supported");
|
||||
}
|
||||
|
||||
@@ -439,11 +438,16 @@ class ConstExprEvaluator {
|
||||
{
|
||||
try {
|
||||
$name = $expr->name;
|
||||
if (! is_null($name) && isset($name)) {
|
||||
if (array_key_exists($name, get_defined_vars())) {
|
||||
return $$name;
|
||||
}
|
||||
|
||||
if (array_key_exists($name, $GLOBALS)) {
|
||||
global $$name;
|
||||
return $$name;
|
||||
}
|
||||
} catch (\Throwable $t) {}
|
||||
} catch (\Throwable $t) {
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
@@ -452,15 +456,15 @@ class ConstExprEvaluator {
|
||||
private function evaluateStaticCall(Expr\StaticCall $expr)
|
||||
{
|
||||
try {
|
||||
$classname = $expr->class->name;
|
||||
$class = $expr->class->name;
|
||||
if ($expr->name instanceof Identifier){
|
||||
$methodname = $expr->name->name;
|
||||
$method = $expr->name->name;
|
||||
} else {
|
||||
$methodname = $this->evaluate($expr->name);
|
||||
$method = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
$static_call_description = "$classname::$methodname";
|
||||
if (! in_array($static_call_description, $this->staticcalls_whitelist)){
|
||||
$static_call_description = "$class::$method";
|
||||
if (! in_array($static_call_description, $this->staticCallsWhitelist)){
|
||||
throw new Exception("StaticCall $static_call_description not supported");
|
||||
}
|
||||
|
||||
@@ -470,8 +474,8 @@ class ConstExprEvaluator {
|
||||
$args[]=$arg->value->value;
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($classname);
|
||||
$method = $class->getMethod($methodname);
|
||||
$class = new \ReflectionClass($class);
|
||||
$method = $class->getMethod($method);
|
||||
if ($method->isPublic()){
|
||||
return $method->invokeArgs(null, $args);
|
||||
}
|
||||
@@ -480,59 +484,79 @@ class ConstExprEvaluator {
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluatePropertyFetch(Expr\NullsafePropertyFetch|Expr\PropertyFetch $expr)
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr\NullsafePropertyFetch|\PhpParser\Node\Expr\PropertyFetch $expr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function evaluatePropertyFetch($expr)
|
||||
{
|
||||
try {
|
||||
$var = $this->evaluateVariable($expr->var);
|
||||
if (is_null($var)) {
|
||||
return null;
|
||||
}
|
||||
$var = $this->evaluate($expr->var);
|
||||
} catch (\Throwable $t) {
|
||||
$var = null;
|
||||
}
|
||||
|
||||
if ($expr->name instanceof Identifier){
|
||||
$name = $expr->name->name;
|
||||
} else {
|
||||
$name = $this->evaluate($expr->name);
|
||||
}
|
||||
if (! is_null($var)) {
|
||||
try {
|
||||
if ($expr->name instanceof Identifier) {
|
||||
$name = $expr->name->name;
|
||||
} else {
|
||||
$name = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
$reflectionClass = new \ReflectionClass(get_class($var));
|
||||
$property = $reflectionClass->getProperty($name);
|
||||
if ($property->isPublic()){
|
||||
return $property->getValue($var);
|
||||
$reflectionClass = new \ReflectionClass(get_class($var));
|
||||
$property = $reflectionClass->getProperty($name);
|
||||
if ($property->isPublic()) {
|
||||
return $property->getValue($var);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $t) {}
|
||||
catch (\Throwable $t) {}
|
||||
} else if ($expr instanceof Expr\NullsafePropertyFetch){
|
||||
return null;
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateMethodCall(Expr\MethodCall|Expr\NullsafeMethodCall $expr)
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\NullsafeMethodCall $expr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function evaluateMethodCall($expr)
|
||||
{
|
||||
try {
|
||||
$var = $this->evaluateVariable($expr->var);
|
||||
if (is_null($var)) {
|
||||
return null;
|
||||
}
|
||||
$var = $this->evaluate($expr->var);
|
||||
} catch (\Throwable $t) {
|
||||
$var = null;
|
||||
}
|
||||
|
||||
$args=[];
|
||||
foreach ($expr->args as $arg){
|
||||
if (! is_null($var)) {
|
||||
try {
|
||||
$args = [];
|
||||
foreach ($expr->args as $arg) {
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$args[]=$arg->value->value;
|
||||
$args[] = $arg->value->value;
|
||||
}
|
||||
|
||||
if ($expr->name instanceof Identifier){
|
||||
if ($expr->name instanceof Identifier) {
|
||||
$name = $expr->name->name;
|
||||
} else {
|
||||
$name = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
$reflectionClass = new \ReflectionClass(get_class($var));
|
||||
$method = $reflectionClass->getMethod($name);
|
||||
if ($method->isPublic()){
|
||||
return $method->invokeArgs($var, $args);
|
||||
if ($method->isPublic()) {
|
||||
return $method->invokeArgs($var, $args);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $t) {}
|
||||
catch (\Throwable $t) {}
|
||||
} else if ($expr instanceof Expr\NullsafeMethodCall){
|
||||
return null;
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
16
sources/PhpParser/Evaluation/IdenticalEvaluator.php
Normal file
16
sources/PhpParser/Evaluation/IdenticalEvaluator.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\PhpParser\Evaluation;
|
||||
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
|
||||
class IdenticalEvaluator extends BinaryOpEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Identical::class;
|
||||
}
|
||||
|
||||
function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed
|
||||
{
|
||||
return $left === $right;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,12 @@ class IssetEvaluator extends AbstractExprEvaluator {
|
||||
/** @var Isset_ $oExpr */
|
||||
|
||||
foreach ($oExpr->vars as $oVar){
|
||||
$var = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oVar);
|
||||
if (! isset($var)){
|
||||
try{
|
||||
$var = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oVar);
|
||||
if (is_null($var)){
|
||||
return false;
|
||||
}
|
||||
} catch (\Throwable $t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,19 @@ class PhpExpressionEvaluator {
|
||||
|
||||
/** @var iExprEvaluator[] $aPhpParserEvaluators */
|
||||
private static array $aPhpParserEvaluators;
|
||||
private int $iMode=self::ITOP_ALGO;
|
||||
|
||||
protected function __construct() {
|
||||
}
|
||||
|
||||
const LIB_AND_FALLBACK=1;
|
||||
const LIB_ONLY=2;
|
||||
const ITOP_ALGO=3;
|
||||
public function SetMode($iMode)
|
||||
{
|
||||
$this->iMode =$iMode;
|
||||
}
|
||||
|
||||
final public static function GetInstance(): PhpExpressionEvaluator {
|
||||
if (!isset(static::$oInstance)) {
|
||||
static::$oInstance = new static();
|
||||
@@ -58,13 +67,13 @@ class PhpExpressionEvaluator {
|
||||
static::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
public function EvaluateExpression(Expr $oExpression, int $iMode=self::LIB_AND_FALLBACK) : mixed
|
||||
public function EvaluateExpression(Expr $oExpression) : mixed
|
||||
{
|
||||
if ($iMode==self::ITOP_ALGO){
|
||||
if ($this->iMode===self::ITOP_ALGO){
|
||||
return $this->EvaluateExpressionLocally($oExpression);
|
||||
}
|
||||
|
||||
if ($iMode==self::LIB_ONLY){
|
||||
if ($this->iMode==self::LIB_ONLY){
|
||||
$oConstExprEvaluator = new ConstExprEvaluator();
|
||||
} else {
|
||||
$oConstExprEvaluator = new ConstExprEvaluator([$this, "EvaluateExpressionLocally"]);
|
||||
@@ -97,10 +106,7 @@ class PhpExpressionEvaluator {
|
||||
return $this->ParseAndEvaluateExpression($sBooleanExpr);
|
||||
}
|
||||
|
||||
const LIB_AND_FALLBACK=1;
|
||||
const LIB_ONLY=2;
|
||||
const ITOP_ALGO=3;
|
||||
public function ParseAndEvaluateExpression(string $sExpr, int $iMode=self::LIB_AND_FALLBACK) : mixed
|
||||
public function ParseAndEvaluateExpression(string $sExpr) : mixed
|
||||
{
|
||||
$sPhpContent = <<<PHP
|
||||
<?php
|
||||
@@ -109,7 +115,7 @@ PHP;
|
||||
try{
|
||||
$aNodes = ModuleFileParser::GetInstance()->ParsePhpCode($sPhpContent);
|
||||
$oExpr = $aNodes[0];
|
||||
return $this->EvaluateExpression($oExpr->expr, $iMode);
|
||||
return $this->EvaluateExpression($oExpr->expr);
|
||||
} catch (\Throwable $t) {
|
||||
throw new ModuleFileReaderException("Eval of '$sExpr' caused an error:".$t->getMessage());
|
||||
}
|
||||
|
||||
@@ -9,19 +9,20 @@ class VariableEvaluator extends AbstractExprEvaluator {
|
||||
public function GetHandledExpressionType(): ?string {
|
||||
return Variable::class;
|
||||
}
|
||||
|
||||
public function Evaluate(Expr $oExpr): mixed {
|
||||
/** @var Variable $oExpr */
|
||||
if (is_null($oExpr->name)){
|
||||
return null;
|
||||
$sName = $oExpr->name;
|
||||
|
||||
if (array_key_exists($sName, get_defined_vars())) {
|
||||
return $$sName;
|
||||
}
|
||||
|
||||
if (! isset($oExpr->name)) {
|
||||
return null;
|
||||
if (array_key_exists($sName, $GLOBALS)) {
|
||||
global $$sName;
|
||||
return $$sName;
|
||||
}
|
||||
|
||||
$sVarname=$oExpr->name;
|
||||
global $$sVarname;
|
||||
return $$sVarname;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,7 @@ class ModuleFileReaderTest extends ItopDataTestCase
|
||||
$this->assertEquals('Bridge - Request management ITIL + Incident management ITIL', $aRes[2]['label'] ?? null);
|
||||
}
|
||||
|
||||
/*public function testAllReadModuleFileConfiguration()
|
||||
public function testAllReadModuleFileConfiguration()
|
||||
{
|
||||
$_SERVER=[
|
||||
'SERVER_NAME' => 'titi'
|
||||
@@ -54,7 +54,7 @@ class ModuleFileReaderTest extends ItopDataTestCase
|
||||
}
|
||||
|
||||
$this->assertEquals([], $aErrors, var_export($aErrors, true));
|
||||
}*/
|
||||
}
|
||||
|
||||
public static function ReadModuleFileConfigurationFileNameProvider()
|
||||
{
|
||||
|
||||
@@ -10,6 +10,12 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
private static $PRIVATE_STATIC_PROPERTY = 123;
|
||||
private const PRIVATE_CONSTANT = 123;
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown(); // TODO: Change the autogenerated stub
|
||||
PhpExpressionEvaluator::GetInstance()->SetMode(PhpExpressionEvaluator::ITOP_ALGO);
|
||||
}
|
||||
|
||||
public static function EvaluateExpressionProvider() {
|
||||
return [
|
||||
'Array: [1000 => "a"]' => ['sExpression' => '[1000 => "a"]'],
|
||||
@@ -19,7 +25,7 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
'BinaryOperator: false|true' => [ 'sExpression' => 'false|true'],
|
||||
'BinaryOperator: false||true' => [ 'sExpression' => 'false||true'],
|
||||
'BinaryOperator: false&&true' => [ 'sExpression' => 'false&&true'],
|
||||
'BinaryOperator: true&&true&&true&&false' => [ 'sExpression' => 'true&&true&&true&&false'],
|
||||
'BinaryOperator: true&&true&&true&&false' => [ 'sExpression' => 'true && true && true && false'],
|
||||
'BinaryOperator: false&true' => [ 'sExpression' => 'false&true'],
|
||||
'BinaryOperator: ! true' => [ 'sExpression' => '! true'],
|
||||
'BinaryOperator: 10 * 5' => [ 'sExpression' => '10 * 5'],
|
||||
@@ -30,6 +36,7 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
'BinaryOperator: PHP_VERSION_ID != PHP_VERSION_ID' => [ 'sExpression' => 'PHP_VERSION_ID != PHP_VERSION_ID'],
|
||||
'BitwiseNot: ~3' => ['sExpression' => '~3'],
|
||||
'BitwiseXor: 3^2' => ['sExpression' => '3^2'],
|
||||
'BooleanAnd: true && false' => ['sExpression' => 'true && false'],
|
||||
'Cast: (array)3' => ['sExpression' => '(array)3'],
|
||||
'Cast: (bool)1' => ['sExpression' => '(bool)1'],
|
||||
'Cast: (bool)0' => ['sExpression' => '(bool)0'],
|
||||
@@ -48,14 +55,21 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
],
|
||||
'Coalesce: $oNullVar ?? 1' => ['sExpression' => '$oNullVar ?? 1', 1],
|
||||
'Coalesce: $oNonNullVar ?? 1' => ['sExpression' => '$oNonNullVar ?? 1', 1],
|
||||
'Coalesce: $_SERVER["toto"] ?? 1' => ['sExpression' => '$_SERVER["toto"] ?? 1', "titi"],
|
||||
'Coalesce: $_SERVER["unknown_key"] ?? 1' => ['sExpression' => '$_SERVER["unknown_key"] ?? 1', 1],
|
||||
'Coalesce: $oGlobalNonNullVar ?? 1' => ['sExpression' => '$oGlobalNonNullVar ?? 1', "a"],
|
||||
'Coalesce: $oGlobalNullVar ?? 1' => ['sExpression' => '$oGlobalNullVar ?? 1', 1],
|
||||
'Concat: "a"."b"' => ['sExpression' => '"a"."b"'],
|
||||
'ConstFetch: false' => [ 'sExpression' => 'false'],
|
||||
'ConstFetch: (false)' => [ 'sExpression' => 'false'],
|
||||
'ConstFetch: true' => [ 'sExpression' => 'true'],
|
||||
'ConstFetch: (true)' => [ 'sExpression' => 'true'],
|
||||
'Equal: 1 == true' => [ 'sExpression' => '1 == true', true],
|
||||
'Equal: 1 == false' => [ 'sExpression' => '1 == false', false],
|
||||
'FuncCall: function_exists(\'ldap_connect\')' => [ 'sExpression' => 'function_exists(\'ldap_connect\')'],
|
||||
'FuncCall: function_exists(\'gabuzomeushouldnotexist\')' => [ 'sExpression' => 'function_exists(\'gabuzomeushouldnotexist\')'],
|
||||
'Identical: 1==="1"' => ['sExpression' => '1==="1"', false],
|
||||
'Identical: "1"==="1"' => ['sExpression' => '"1"==="1"', true],
|
||||
'Isset: isset($oNonNullVar)' => ['sExpression' => 'isset($oNonNullVar)', false],
|
||||
'Isset: isset($oGlobalNonNullVar)' => ['sExpression' => 'isset($oGlobalNonNullVar)', true],
|
||||
'Isset: isset($a, $_SERVER)' => ['sExpression' => 'isset($a, $_SERVER)', false],
|
||||
@@ -85,6 +99,7 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
'Variable: $_SERVER' => ['sExpression' => '$_SERVER', ['toto' => 'titi']],
|
||||
'Variable: $oNonNullVar' => ['sExpression' => '$oNonNullVar', null],
|
||||
'Variable: $oGlobalNonNullVar' => ['sExpression' => '$oGlobalNonNullVar', "a"],
|
||||
'Variable: $oEvaluationFakeClass' => ['sExpression' => '$oEvaluationFakeClass', new EvaluationFakeClass()],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -116,6 +131,10 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
{
|
||||
global $oGlobalNonNullVar;
|
||||
$oGlobalNonNullVar="a";
|
||||
|
||||
global $oGlobalNullVar;
|
||||
$oGlobalNullVar=null;
|
||||
|
||||
$oNonNullVar="a";
|
||||
|
||||
$oNullVar=null;
|
||||
@@ -126,7 +145,8 @@ class PhpExpressionEvaluatorTest extends ItopDataTestCase {
|
||||
global $oEvaluationFakeClass;
|
||||
$oEvaluationFakeClass = new EvaluationFakeClass();
|
||||
|
||||
$res = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateExpression($sExpression, $iMode);
|
||||
PhpExpressionEvaluator::GetInstance()->SetMode($iMode);
|
||||
$res = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateExpression($sExpression);
|
||||
if ($forced_expected === "NOTPROVIDED"){
|
||||
$this->assertEquals($this->UnprotectedComputeExpression($sExpression), $res, $sExpression);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user