Files
iTop/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php
2025-09-05 15:21:15 +02:00

123 lines
3.5 KiB
PHP

<?php
namespace Combodo\iTop\PhpParser\Evaluation;
use ModuleFileParser;
use ModuleFileReaderException;
use PhpParser\ConstExprEvaluator;
use PhpParser\Node\Expr;
class PhpExpressionEvaluator {
private static PhpExpressionEvaluator $oInstance;
/** @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();
static::$aPhpParserEvaluators=[];
foreach (glob(__DIR__ . "/**Evaluator.php") as $sFile){
require_once $sFile;
require_once $sFile;
$sNamespace = 'Combodo\\iTop\PhpParser\\Evaluation\\';
$sClass = $sNamespace. str_replace(".php", "", basename($sFile));
$oReflectionClass = new \ReflectionClass($sClass);
if ($oReflectionClass->isInstantiable()
&& $oReflectionClass->implementsInterface(iExprEvaluator::class)){
$oClass = new $sClass;
if (! is_null($oClass->GetHandledExpressionType())){
static::RegisterEvaluator($oClass, $oClass->GetHandledExpressionType());
}
if (! is_null($oClass->GetHandledExpressionTypes())) {
foreach ($oClass->GetHandledExpressionTypes() as $sHandledExpressionType){
static::RegisterEvaluator($oClass, $sHandledExpressionType);
}
}
}
}
}
return static::$oInstance;
}
private static function RegisterEvaluator(iExprEvaluator $oClass, string $sHandledExpressionType)
{
if (array_key_exists($sHandledExpressionType, static::$aPhpParserEvaluators)){
throw new \CoreException("Another Evaluator class already deals with $sHandledExpressionType");
}
static::$aPhpParserEvaluators[$sHandledExpressionType] = $oClass;
}
final public static function SetInstance(?PhpExpressionEvaluator $oInstance): void {
static::$oInstance = $oInstance;
}
public function EvaluateExpression(Expr $oExpression) : mixed
{
if ($this->iMode===self::ITOP_ALGO){
return $this->EvaluateExpressionLocally($oExpression);
}
if ($this->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;
if (is_null($oPhpParserEvaluator)){
return $oExpression->value;
}
return $oPhpParserEvaluator->Evaluate($oExpression);
}
/**
* @param string $sBooleanExpr
*
* @return bool
* @throws \ModuleFileReaderException
*/
public function ParseAndEvaluateBooleanExpression(string $sBooleanExpr) : bool
{
return $this->ParseAndEvaluateExpression($sBooleanExpr);
}
public function ParseAndEvaluateExpression(string $sExpr) : mixed
{
$sPhpContent = <<<PHP
<?php
$sExpr;
PHP;
try{
$aNodes = ModuleFileParser::GetInstance()->ParsePhpCode($sPhpContent);
$oExpr = $aNodes[0];
return $this->EvaluateExpression($oExpr->expr);
} catch (\Throwable $t) {
throw new ModuleFileReaderException("Eval of '$sExpr' caused an error:".$t->getMessage());
}
}
}