Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 81 additions & 9 deletions lib/PhpParser/ConstExprEvaluator.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
* following node types:
*
* * All Scalar\MagicConst\* nodes.
* * Expr\ConstFetch nodes. Only null/false/true are already handled by this class.
* * Expr\ClassConstFetch nodes.
*
* The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate.
*
Expand All @@ -28,7 +26,7 @@
*/
class ConstExprEvaluator {
/** @var callable|null */
private $fallbackEvaluator;
protected $fallbackEvaluator;

/**
* Create a constant expression evaluator.
Expand Down Expand Up @@ -103,7 +101,7 @@ public function evaluateDirectly(Expr $expr) {
}

/** @return mixed */
private function evaluate(Expr $expr) {
protected function evaluate(Expr $expr) {
if ($expr instanceof Scalar\Int_
|| $expr instanceof Scalar\Float_
|| $expr instanceof Scalar\String_
Expand Down Expand Up @@ -145,6 +143,14 @@ private function evaluate(Expr $expr) {
return $this->evaluateConstFetch($expr);
}

if ($expr instanceof Expr\ClassConstFetch) {
return $this->evaluateClassConstFetch($expr);
}

if ($expr instanceof Expr\Cast) {
return $this->evaluateCast($expr);
}

return ($this->fallbackEvaluator)($expr);
}

Expand Down Expand Up @@ -225,11 +231,77 @@ private function evaluateBinaryOp(Expr\BinaryOp $expr) {

/** @return mixed */
private function evaluateConstFetch(Expr\ConstFetch $expr) {
$name = $expr->name->toLowerString();
switch ($name) {
case 'null': return null;
case 'false': return false;
case 'true': return true;
try {
$name = $expr->name->name;

if (defined($name)) {
return constant($name);
}
} catch (\Throwable $t) {
}

return ($this->fallbackEvaluator)($expr);
}

/** @return mixed */
private function evaluateClassConstFetch(Expr\ClassConstFetch $expr) {
try {
$classname = $expr->class->name;
$property = $expr->name->name;

if ('class' === $property) {
return $classname;
}

if (class_exists($classname)) {
$class = new \ReflectionClass($classname);
if (array_key_exists($property, $class->getConstants())) {
$oReflectionConstant = $class->getReflectionConstant($property);
if ($oReflectionConstant->isPublic()) {
return $class->getConstant($property);
}
}
}
} catch (\Throwable $t) {
}

return ($this->fallbackEvaluator)($expr);
}

/** @return mixed */
private function evaluateCast(Expr\Cast $expr) {
try {
$subexpr = $this->evaluate($expr->expr);
$type = get_class($expr);
switch ($type) {
case Expr\Cast\Array_::class:
return (array) $subexpr;

case Expr\Cast\Bool_::class:
return (bool) $subexpr;

case Expr\Cast\Double::class:
switch ($expr->getAttribute("kind")) {
case Expr\Cast\Double::KIND_DOUBLE:
return (float) $subexpr;

case Expr\Cast\Double::KIND_FLOAT:
case Expr\Cast\Double::KIND_REAL:
return (float) $subexpr;
}

break;

case Expr\Cast\Int_::class:
return (int) $subexpr;

case Expr\Cast\Object_::class:
return (object) $subexpr;

case Expr\Cast\String_::class:
return (string) $subexpr;
}
} catch (\Throwable $t) {
}

return ($this->fallbackEvaluator)($expr);
Expand Down
6 changes: 6 additions & 0 deletions lib/PhpParser/ExprEvaluationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php declare(strict_types=1);

namespace PhpParser;

class ExprEvaluationException extends \Exception {
}
Loading