diff --git a/sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php b/sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php index e3e67378b5..5217dc0991 100644 --- a/sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php +++ b/sources/PhpParser/Evaluation/ClassConstFetchEvaluator.php @@ -16,6 +16,10 @@ class ClassConstFetchEvaluator extends AbstractExprEvaluator { $sClassName = $oExpr->class->name; $sProperty = $oExpr->name->name; + if ('class' === $sProperty){ + return $sClassName; + } + if (class_exists($sClassName)){ $class = new \ReflectionClass($sClassName); if (array_key_exists($sProperty, $class->getConstants())) { @@ -26,10 +30,6 @@ class ClassConstFetchEvaluator extends AbstractExprEvaluator { } } - if ('class' === $sProperty){ - return $sClassName; - } - return null; } } \ No newline at end of file diff --git a/sources/PhpParser/Evaluation/FuncCallEvaluator.php b/sources/PhpParser/Evaluation/FuncCallEvaluator.php index 8d185eef1f..a206cf36a8 100644 --- a/sources/PhpParser/Evaluation/FuncCallEvaluator.php +++ b/sources/PhpParser/Evaluation/FuncCallEvaluator.php @@ -5,9 +5,17 @@ namespace Combodo\iTop\PhpParser\Evaluation; use ModuleFileReaderException; use PhpParser\Node\Expr; use PhpParser\Node\Expr\FuncCall; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; use ReflectionFunction; class FuncCallEvaluator extends AbstractExprEvaluator { + public const WHITELIST=[ + "function_exists", + "class_exists", + "method_exists" + ]; + public function GetHandledExpressionType(): ?string { return FuncCall::class; } @@ -15,9 +23,12 @@ class FuncCallEvaluator extends AbstractExprEvaluator { public function Evaluate(Expr $oExpr): mixed { /** @var FuncCall $oExpr */ - $sFunction = $oExpr->name->name; - $aWhiteList = ["function_exists", "class_exists", "method_exists"]; - if (! in_array($sFunction, $aWhiteList)){ + if ($oExpr->name instanceof Name){ + $sFunction = $oExpr->name->name; + } else { + $sFunction = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); + } + if (! in_array($sFunction, self::WHITELIST)){ throw new ModuleFileReaderException("FuncCall $sFunction not supported"); } diff --git a/sources/PhpParser/Evaluation/MethodCallEvaluator.php b/sources/PhpParser/Evaluation/MethodCallEvaluator.php index 025f015d38..0e03406bc2 100644 --- a/sources/PhpParser/Evaluation/MethodCallEvaluator.php +++ b/sources/PhpParser/Evaluation/MethodCallEvaluator.php @@ -4,33 +4,45 @@ namespace Combodo\iTop\PhpParser\Evaluation; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Identifier; use ReflectionClass; -class MethodCallEvaluator extends AbstractExprEvaluator { +class MethodCallEvaluator extends AbstractExprEvaluator { public function GetHandledExpressionType(): ?string { - return MethodCall::class; + return null; + } + + public function GetHandledExpressionTypes(): ?array { + return [MethodCall::class, Expr\NullsafeMethodCall::class]; } public function Evaluate(Expr $oExpr): mixed { - /** @var MethodCall $oExpr */ - $oVar = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->var); if (is_null($oVar)) { return null; } - $aArgs = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->args); - $sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); - $oReflectionClass = new ReflectionClass(get_class($oVar)); - - $oMethods = $oReflectionClass->getMethods(); - if (array_key_exists($sName, $oMethods)){ - $oMethods = $oMethods[$sName]; - if ($oMethods->isPublic()){ - return $oMethods->invokeArgs($oVar, $aArgs); - } + $aArgs=[]; + foreach ($oExpr->args as $arg){ + /** @var \PhpParser\Node\Arg $arg */ + $aArgs[]=$arg->value->value; } + if ($oExpr->name instanceof Identifier){ + $sName = $oExpr->name->name; + } else { + $sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); + } + + $oReflectionClass = new ReflectionClass(get_class($oVar)); + try{ + $oMethod = $oReflectionClass->getMethod($sName); + if ($oMethod->isPublic()){ + return $oMethod->invokeArgs($oVar, $aArgs); + } + } catch (\ReflectionException $t) {} + return null; } } \ No newline at end of file diff --git a/sources/PhpParser/Evaluation/NullsafeMethodCallEvaluator.php b/sources/PhpParser/Evaluation/NullsafeMethodCallEvaluator.php deleted file mode 100644 index 77788ee039..0000000000 --- a/sources/PhpParser/Evaluation/NullsafeMethodCallEvaluator.php +++ /dev/null @@ -1,36 +0,0 @@ -EvaluateExpression($oExpr->var); - if (is_null($oVar)) { - return null; - } - - $aArgs = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->args); - $sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); - $oReflectionClass = new ReflectionClass(get_class($oVar)); - - $oMethods = $oReflectionClass->getMethods(); - if (array_key_exists($sName, $oMethods)){ - $oMethods = $oMethods[$sName]; - if ($oMethods->isPublic()){ - return $oMethods->invokeArgs($oVar, $aArgs); - } - } - - return null; - } -} \ No newline at end of file diff --git a/sources/PhpParser/Evaluation/NullsafePropertyFetchEvaluator.php b/sources/PhpParser/Evaluation/NullsafePropertyFetchEvaluator.php deleted file mode 100644 index 8b956390bf..0000000000 --- a/sources/PhpParser/Evaluation/NullsafePropertyFetchEvaluator.php +++ /dev/null @@ -1,35 +0,0 @@ -EvaluateExpression($oExpr->var); - if (is_null($oVar)) { - return null; - } - - $sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); - $oReflectionClass = new ReflectionClass(get_class($oVar)); - - $oProperties = $oReflectionClass->getProperties(); - if (array_key_exists($sName, $oProperties)){ - $oProperty = $oProperties[$sName]; - if ($oProperty->isPublic()){ - return $oProperty->getValue($oVar); - } - } - - return null; - } -} \ No newline at end of file diff --git a/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php b/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php index f047995037..8abad02632 100644 --- a/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php +++ b/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php @@ -4,6 +4,7 @@ namespace Combodo\iTop\PhpParser\Evaluation; use ModuleFileParser; use ModuleFileReaderException; +use PhpParser\ConstExprEvaluator; use PhpParser\Node\Expr; class PhpExpressionEvaluator { @@ -57,7 +58,24 @@ class PhpExpressionEvaluator { static::$oInstance = $oInstance; } - public function EvaluateExpression(Expr $oExpression) : mixed + public function EvaluateExpression(Expr $oExpression, int $iMode=self::LIB_AND_FALLBACK) : mixed + { + if ($iMode==self::ITOP_ALGO){ + return $this->EvaluateExpressionLocally($oExpression); + } + + if ($iMode==self::LIB_ONLY){ + $oConstExprEvaluator = new ConstExprEvaluator(); + } else { + $oConstExprEvaluator = new ConstExprEvaluator([$this, "EvaluateExpressionLocally"]); + } + + $oConstExprEvaluator->setFunctionsWhitelist(FuncCallEvaluator::WHITELIST); + $oConstExprEvaluator->setStaticcallsWhitelist(StaticCallEvaluator::WHITELIST); + return $oConstExprEvaluator->evaluateDirectly($oExpression); + } + + public function EvaluateExpressionLocally(Expr $oExpression) : mixed { $sClass = get_class($oExpression); $oPhpParserEvaluator = static::$aPhpParserEvaluators[$sClass] ?? null; @@ -79,7 +97,10 @@ class PhpExpressionEvaluator { return $this->ParseAndEvaluateExpression($sBooleanExpr); } - public function ParseAndEvaluateExpression(string $sExpr) : mixed + 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 { $sPhpContent = <<ParsePhpCode($sPhpContent); $oExpr = $aNodes[0]; - return $this->EvaluateExpression($oExpr->expr); + return $this->EvaluateExpression($oExpr->expr, $iMode); } catch (\Throwable $t) { throw new ModuleFileReaderException("Eval of '$sExpr' caused an error:".$t->getMessage()); } diff --git a/sources/PhpParser/Evaluation/PropertyFetchEvaluator.php b/sources/PhpParser/Evaluation/PropertyFetchEvaluator.php index 0724eb6510..543b626f01 100644 --- a/sources/PhpParser/Evaluation/PropertyFetchEvaluator.php +++ b/sources/PhpParser/Evaluation/PropertyFetchEvaluator.php @@ -4,44 +4,38 @@ namespace Combodo\iTop\PhpParser\Evaluation; use PhpParser\Node\Expr; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Identifier; use ReflectionClass; class PropertyFetchEvaluator extends AbstractExprEvaluator { public function GetHandledExpressionType(): ?string { - return PropertyFetch::class; + return null; + } + + public function GetHandledExpressionTypes(): ?array { + return [PropertyFetch::class, Expr\NullsafePropertyFetch::class]; } public function Evaluate(Expr $oExpr): mixed { - /** @var PropertyFetch $oExpr */ - $oVar = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->var); if (is_null($oVar)) { return null; } - $sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); - $oReflectionClass = new ReflectionClass(get_class($oVar)); + if ($oExpr->name instanceof Identifier){ + $sName = $oExpr->name->name; + } else { + $sName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); + } - $oProperties = $oReflectionClass->getProperties(); - if (array_key_exists($sName, $oProperties)){ - $oProperty = $oProperties[$sName]; + $oReflectionClass = new ReflectionClass(get_class($oVar)); + try{ + $oProperty = $oReflectionClass->getProperty($sName); if ($oProperty->isPublic()){ return $oProperty->getValue($oVar); } + } catch (\ReflectionException $t) {} - return null; - } - - $aArgs=[]; - - $oMethods = $oReflectionClass->getMethods(); - if (array_key_exists($sName, $oMethods)){ - $oMethod = $oMethods[$sName]; - if ($oMethod->isPublic()){ - return $oMethod->invokeArgs(null, $aArgs); - } - - return null; - } + return null; } } \ No newline at end of file diff --git a/sources/PhpParser/Evaluation/StaticCallEvaluator.php b/sources/PhpParser/Evaluation/StaticCallEvaluator.php index f66c37162e..3d5bc5f35d 100644 --- a/sources/PhpParser/Evaluation/StaticCallEvaluator.php +++ b/sources/PhpParser/Evaluation/StaticCallEvaluator.php @@ -5,8 +5,14 @@ namespace Combodo\iTop\PhpParser\Evaluation; use ModuleFileReaderException; use PhpParser\Node\Expr; use PhpParser\Node\Expr\StaticCall; +use PhpParser\Node\Identifier; class StaticCallEvaluator extends AbstractExprEvaluator { + public const WHITELIST=[ + "SetupInfo::ModuleIsSelected", + "utils::GetItopVersionWikiSyntax" + ]; + public function GetHandledExpressionType(): ?string { return StaticCall::class; } @@ -15,11 +21,14 @@ class StaticCallEvaluator extends AbstractExprEvaluator { /** @var StaticCall $oExpr */ $sClassName = $oExpr->class->name; - $sMethodName = $oExpr->name->name; + if ($oExpr->name instanceof Identifier){ + $sMethodName = $oExpr->name->name; + } else { + $sMethodName = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); + } - $aWhiteList = ["SetupInfo::ModuleIsSelected", "utils::GetItopVersionWikiSyntax"]; $sStaticCallDescription = "$sClassName::$sMethodName"; - if (! in_array($sStaticCallDescription, $aWhiteList)){ + if (! in_array($sStaticCallDescription, self::WHITELIST)){ throw new ModuleFileReaderException("StaticCall $sStaticCallDescription not supported"); } diff --git a/sources/PhpParser/Evaluation/StaticPropertyFetchEvaluator.php b/sources/PhpParser/Evaluation/StaticPropertyFetchEvaluator.php index 93090342a2..8ebd5350e1 100644 --- a/sources/PhpParser/Evaluation/StaticPropertyFetchEvaluator.php +++ b/sources/PhpParser/Evaluation/StaticPropertyFetchEvaluator.php @@ -4,6 +4,7 @@ namespace Combodo\iTop\PhpParser\Evaluation; use PhpParser\Node\Expr; use PhpParser\Node\Expr\StaticPropertyFetch; +use PhpParser\Node\Identifier; class StaticPropertyFetchEvaluator extends AbstractExprEvaluator { public function GetHandledExpressionType(): ?string { @@ -14,7 +15,11 @@ class StaticPropertyFetchEvaluator extends AbstractExprEvaluator { /** @var StaticPropertyFetch $oExpr */ $sClassName = $oExpr->class->name; - $sProperty = $oExpr->name->name; + if ($oExpr->name instanceof Identifier){ + $sProperty = $oExpr->name->name; + } else { + $sProperty = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->name); + } if (class_exists($sClassName)){ $class = new \ReflectionClass($sClassName); diff --git a/sources/PhpParser/Evaluation/VariableEvaluator.php b/sources/PhpParser/Evaluation/VariableEvaluator.php index 92444ec5b3..967224c9b4 100644 --- a/sources/PhpParser/Evaluation/VariableEvaluator.php +++ b/sources/PhpParser/Evaluation/VariableEvaluator.php @@ -21,7 +21,6 @@ class VariableEvaluator extends AbstractExprEvaluator { } $sVarname=$oExpr->name; - global $$sVarname; return $$sVarname; }