fix(compiler): 修复trait中类常量访问的命名空间解析问题

- 为getNamespacedClassName方法添加可选的当前命名空间参数
- 在gen_stub.php中传递当前类信息到getClassConstValue调用
- 在Translator.php中使用当前类的命名空间信息进行类常量查找
- 在类注册完成后清理ClassInfo::$currentClass避免污染
- 修复self引用时的默认值解析逻辑
pull/1/head
韩天峰 3 months ago
parent ec5f393a27
commit ce7d254709
  1. 6
      src/Php/CompilerBase.php
  2. 8
      src/Php/Translator.php
  3. 9
      src/gen_stub.php
  4. 38
      tests/aot/trait/011.phpt

@ -892,7 +892,7 @@ class CompilerBase extends \PhpAot\Core\Translator
return strtolower($fullClassName . '::' . $method); return strtolower($fullClassName . '::' . $method);
} }
public function getNamespacedClassName(string $class): string public function getNamespacedClassName(string $class, string $currentNamespace = ''): string
{ {
if ($class === '') { if ($class === '') {
$this->error('Class name can not be empty'); $this->error('Class name can not be empty');
@ -920,7 +920,9 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} }
$currentNamespace = $this->namespace; if (!$currentNamespace) {
$currentNamespace = $this->namespace;
}
if (!empty($currentNamespace)) { if (!empty($currentNamespace)) {
return trim($currentNamespace, '\\') . '\\' . $class; return trim($currentNamespace, '\\') . '\\' . $class;
} }

@ -1195,9 +1195,13 @@ CODE;
* 仅用于 gen_stub 脚本 * 仅用于 gen_stub 脚本
* @throws \Exception * @throws \Exception
*/ */
public function getClassConstValue(NodeAbstract $expr, string $class, string $name): mixed public function getClassConstValue(NodeAbstract $expr, string $_class, string $name, string $currentClass): mixed
{ {
$class = $this->getNamespacedClassName($class); $namespace = $this->namespace;
if (!$namespace) {
$namespace = (string)strstr($currentClass, '\\', true);
}
$class = $this->getNamespacedClassName($_class, $namespace);
$nativeConst = $this->findNativeClassConst($expr, $class, $name); $nativeConst = $this->findNativeClassConst($expr, $class, $name);
if ($nativeConst and $expr->hasAttribute('nativeConst')) { if ($nativeConst and $expr->hasAttribute('nativeConst')) {
$constDef = $expr->getAttribute('nativeConst'); $constDef = $expr->getAttribute('nativeConst');

@ -2309,12 +2309,12 @@ class EvaluatedValue
if (isset($allConstInfos[$constName])) { if (isset($allConstInfos[$constName])) {
return $allConstInfos[$constName]->getValue($allConstInfos)->value; return $allConstInfos[$constName]->getValue($allConstInfos)->value;
} else { } else {
return getTranslator()->getClassConstValue($expr, ClassInfo::$currentClass, $expr->name->toString()); return getTranslator()->getClassConstValue($expr, ClassInfo::$currentClass, $expr->name->toString(), ClassInfo::$currentClass);
} }
} elseif ($expr->name->__toString() === 'class') { } elseif ($expr->name->__toString() === 'class') {
return $class; return $class;
} else { } else {
return getTranslator()->getClassConstValue($expr, $class, $expr->name->__toString()); return getTranslator()->getClassConstValue($expr, $class, $expr->name->__toString(), ClassInfo::$currentClass);
} }
} else { } else {
$constName = $expr->name->__toString(); $constName = $expr->name->__toString();
@ -4525,6 +4525,8 @@ class FileInfo {
$this->getMinimumPhpVersionIdCompatibility(), $this->getMinimumPhpVersionIdCompatibility(),
$this->isUndocumentable $this->isUndocumentable
); );
// 清理当前类名,避免污染
ClassInfo::$currentClass = '';
continue; continue;
} }
@ -4582,6 +4584,7 @@ class FileInfo {
foreach ($this->classInfos as $class) { foreach ($this->classInfos as $class) {
ClassInfo::$currentClass = $class->name->toString(); ClassInfo::$currentClass = $class->name->toString();
$code .= "\n" . $class->getRegistration($allConstInfos); $code .= "\n" . $class->getRegistration($allConstInfos);
ClassInfo::$currentClass = '';
} }
return $code; return $code;
@ -4866,7 +4869,7 @@ function parseFunctionLike(
} }
if ($param->default instanceof Expr\ClassConstFetch && $param->default->class->toLowerString() === "self") { if ($param->default instanceof Expr\ClassConstFetch && $param->default->class->toLowerString() === "self") {
$defaultValue = getTranslator()->getClassConstValue($func, $name->className->name, $param->default->name->name); $defaultValue = getTranslator()->getClassConstValue($func, $name->className->name, $param->default->name->name, ClassInfo::$currentClass);
} else { } else {
$defaultValue = $param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null; $defaultValue = $param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null;
} }

@ -0,0 +1,38 @@
--TEST--
trait full class name
--FILE--
<?php
namespace App2 {
trait THello1
{
public const array DATA = [
TraitsTest::NAME => 'Hello 1',
];
public function hello()
{
var_dump(self::DATA);
var_dump(self::DATA[TraitsTest::NAME]);
}
}
class TraitsTest
{
public const NAME = 'test_trait';
use THello1;
}
}
namespace {
function main()
{
$o = new App2\TraitsTest;
$o->hello();
}
}
?>
--EXPECT--
array(1) {
["test_trait"]=>
string(7) "Hello 1"
}
string(7) "Hello 1"
Loading…
Cancel
Save