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);
}
public function getNamespacedClassName(string $class): string
public function getNamespacedClassName(string $class, string $currentNamespace = ''): string
{
if ($class === '') {
$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)) {
return trim($currentNamespace, '\\') . '\\' . $class;
}

@ -1195,9 +1195,13 @@ CODE;
* 仅用于 gen_stub 脚本
* @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);
if ($nativeConst and $expr->hasAttribute('nativeConst')) {
$constDef = $expr->getAttribute('nativeConst');

@ -2309,12 +2309,12 @@ class EvaluatedValue
if (isset($allConstInfos[$constName])) {
return $allConstInfos[$constName]->getValue($allConstInfos)->value;
} 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') {
return $class;
} else {
return getTranslator()->getClassConstValue($expr, $class, $expr->name->__toString());
return getTranslator()->getClassConstValue($expr, $class, $expr->name->__toString(), ClassInfo::$currentClass);
}
} else {
$constName = $expr->name->__toString();
@ -4525,6 +4525,8 @@ class FileInfo {
$this->getMinimumPhpVersionIdCompatibility(),
$this->isUndocumentable
);
// 清理当前类名,避免污染
ClassInfo::$currentClass = '';
continue;
}
@ -4582,6 +4584,7 @@ class FileInfo {
foreach ($this->classInfos as $class) {
ClassInfo::$currentClass = $class->name->toString();
$code .= "\n" . $class->getRegistration($allConstInfos);
ClassInfo::$currentClass = '';
}
return $code;
@ -4866,7 +4869,7 @@ function parseFunctionLike(
}
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 {
$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