- Move getClassConstValue, resolveInheritedClassConst, evaluateClassConstValue methods to ClassConstantValueTrait - Extract getDefinedConstants and getConstValue methods to the new trait - Add ClassConstantValueTrait usage to Translator class - Remove duplicated method implementations from Translator class - Maintain same functionality for class constant evaluation and inheritance resolution - Improve code organization by separating constant-related logic into reusable traitpull/17/head
parent
11d4c23085
commit
6de4dc42bd
2 changed files with 153 additions and 159 deletions
@ -0,0 +1,151 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* This file is part of TypePHP. |
||||||
|
* |
||||||
|
* @link https://www.swoole.com/ |
||||||
|
* @contact service@swoole.com |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace TypePhp\Resolver; |
||||||
|
|
||||||
|
use PhpParser\ConstExprEvaluator; |
||||||
|
use PhpParser\Node; |
||||||
|
use PhpParser\NodeAbstract; |
||||||
|
use TypePhp\Entity\ConstantDef; |
||||||
|
|
||||||
|
trait ClassConstantValueTrait |
||||||
|
{ |
||||||
|
public function getDefinedConstants(): array |
||||||
|
{ |
||||||
|
return $this->internalConstants; |
||||||
|
} |
||||||
|
|
||||||
|
public function getClassConstValue(NodeAbstract $expr, string $_class, string $name, string $currentClass = ''): mixed |
||||||
|
{ |
||||||
|
$namespace = $this->namespace; |
||||||
|
if (!$namespace and $currentClass and !str_contains($_class, '\\')) { |
||||||
|
$namespace = $this->getNamespaceOfClass($currentClass); |
||||||
|
} |
||||||
|
$class = $this->getNamespacedClassName($_class, $namespace); |
||||||
|
$nativeConst = $this->findNativeClassConst($expr, $class, $name); |
||||||
|
if ($nativeConst and $expr->hasAttribute('nativeConst')) { |
||||||
|
$constDef = $expr->getAttribute('nativeConst'); |
||||||
|
if ($constDef->valueExpr !== null) { |
||||||
|
return $this->evaluateClassConstValue($expr, $constDef, $class, $name); |
||||||
|
} |
||||||
|
if ($constDef->class !== '') { |
||||||
|
$refConst = $constDef->class . '::' . $name; |
||||||
|
if (defined($refConst)) { |
||||||
|
return constant($refConst); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if ($this->isInternalClass($class)) { |
||||||
|
$constName = $class . '::' . $name; |
||||||
|
if (defined($constName)) { |
||||||
|
return constant($constName); |
||||||
|
} |
||||||
|
} |
||||||
|
[$inheritedFound, $inherited] = $this->resolveInheritedClassConst($class, $name); |
||||||
|
if ($inheritedFound) { |
||||||
|
return $inherited; |
||||||
|
} |
||||||
|
if ($this->hasClass($class)) { |
||||||
|
$classDef = $this->getClass($class); |
||||||
|
if ($classDef->enum && array_key_exists($name, $classDef->enumCases)) { |
||||||
|
$caseValue = $classDef->enumCases[$name]; |
||||||
|
return $caseValue ?? $name; |
||||||
|
} |
||||||
|
} |
||||||
|
$this->fatalError($expr, "Class constant `{$class}::{$name}` not found"); |
||||||
|
} |
||||||
|
|
||||||
|
/** @return array{bool, mixed} */ |
||||||
|
protected function resolveInheritedClassConst(string $class, string $name): array |
||||||
|
{ |
||||||
|
$current = ltrim($class, '\\'); |
||||||
|
$visited = []; |
||||||
|
while ($current !== '' && $current !== '\\' && !isset($visited[strtolower($current)])) { |
||||||
|
$visited[strtolower($current)] = true; |
||||||
|
if ($this->hasClass($current)) { |
||||||
|
$classDef = $this->getClass($current); |
||||||
|
if ($classDef->hasConstant($name)) { |
||||||
|
$constDef = $classDef->getConstant($name); |
||||||
|
if ($constDef->valueExpr !== null) { |
||||||
|
return [true, $this->evaluateClassConstValue(null, $constDef, $current, $name)]; |
||||||
|
} |
||||||
|
if ($constDef->class !== '' && defined($constDef->class . '::' . $name)) { |
||||||
|
return [true, constant($constDef->class . '::' . $name)]; |
||||||
|
} |
||||||
|
} |
||||||
|
$current = $classDef->extends; |
||||||
|
} elseif (($parent = $this->getParentClass($current)) !== '') { |
||||||
|
$current = $parent; |
||||||
|
} elseif (Reflection::isInternalClass($current)) { |
||||||
|
$constName = $current . '::' . $name; |
||||||
|
if (defined($constName)) { |
||||||
|
return [true, constant($constName)]; |
||||||
|
} |
||||||
|
break; |
||||||
|
} else { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return [false, null]; |
||||||
|
} |
||||||
|
|
||||||
|
protected function evaluateClassConstValue(?NodeAbstract $origin, ConstantDef $constDef, string $class, string $name): mixed |
||||||
|
{ |
||||||
|
$valueExpr = $constDef->valueExpr; |
||||||
|
if (!$valueExpr instanceof Node\Expr) { |
||||||
|
$this->fatalError($origin, "Class constant `{$class}::{$name}` has no constant expression"); |
||||||
|
} |
||||||
|
|
||||||
|
$evaluator = new ConstExprEvaluator(function (Node\Expr $expr) use ($origin, $class) { |
||||||
|
if ($expr instanceof Node\Expr\ConstFetch) { |
||||||
|
$constName = $expr->name->toString(); |
||||||
|
return match (strtolower($constName)) { |
||||||
|
'true' => true, |
||||||
|
'false' => false, |
||||||
|
'null' => null, |
||||||
|
default => defined($constName) |
||||||
|
? constant($constName) |
||||||
|
: throw new \RuntimeException("Constant `{$constName}` not found"), |
||||||
|
}; |
||||||
|
} |
||||||
|
if ($expr instanceof Node\Expr\ClassConstFetch && $expr->class instanceof Node\Name) { |
||||||
|
$constName = $expr->name->toString(); |
||||||
|
$className = $expr->class->toString(); |
||||||
|
if (strcasecmp($className, 'self') === 0) { |
||||||
|
$className = $class; |
||||||
|
} elseif (strcasecmp($className, 'parent') === 0) { |
||||||
|
$className = $this->getParentClass($class); |
||||||
|
} |
||||||
|
return $this->getClassConstValue($origin ?? $expr, $className, $constName, $class); |
||||||
|
} |
||||||
|
throw new \RuntimeException('Unsupported class constant expression'); |
||||||
|
}); |
||||||
|
|
||||||
|
return $evaluator->evaluateDirectly($valueExpr); |
||||||
|
} |
||||||
|
|
||||||
|
public function getConstValue(string $name): mixed |
||||||
|
{ |
||||||
|
if ($this->isInternalConstant($name)) { |
||||||
|
$value = $this->internalConstants[$name]; |
||||||
|
if (is_int($value)) { |
||||||
|
$expr = $this->genIntegerLiteral($value); |
||||||
|
} elseif (is_float($value)) { |
||||||
|
return $value; |
||||||
|
} elseif (is_bool($value)) { |
||||||
|
return $value ? 1 : 0; |
||||||
|
} elseif (is_string($value)) { |
||||||
|
return $this->genCharPtr($value); |
||||||
|
} else { |
||||||
|
$this->error('Unsupported constant type: ' . gettype($value)); |
||||||
|
} |
||||||
|
return $expr; |
||||||
|
} |
||||||
|
throw new \Exception('Constant ' . $name . ' not found'); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue