feat(compiler): 支持类常量继承和访问控制检查

- 添加 ConstantDef 实体类用于表示类常量定义
- 实现 getNativeClassConst 方法支持类常量子类继承查找
- 重构 checkAccessible 方法支持常量访问控制检查
- 集成类常量访问到编译器表达式处理流程
- 添加类常量测试用例验证继承功能
pull/1/head
韩天峰 5 months ago
parent f2647ccbba
commit e7f2760d93
  1. 50
      src/Php/CompilerBase.php
  2. 36
      tests/aot/class-const-002.phpt

@ -11,6 +11,7 @@ namespace PhpAot\Php;
use League\CLImate\CLImate;
use PhpAot\Php\Context\FunctionContext;
use PhpAot\Php\Entity\ClassDef;
use PhpAot\Php\Entity\ConstantDef;
use PhpAot\Php\Entity\FunctionDef;
use PhpAot\Php\Entity\InterfaceDef;
use PhpAot\Php\Entity\MethodDef;
@ -1662,6 +1663,39 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->getNativeName($method, $classDef->namespace, $classDef->name);
}
protected function getNativeClassConst(NodeAbstract $expr, string $class, string $const): string|false
{
if (!$this->hasNativeClass($class)) {
return false;
}
$classDef = $this->getClassDef($class);
$constDef = null;
// 递归查找,若子类中未定义方法,则尝试查找父类是否存在此方法
while ($classDef) {
if (!$classDef->hasConstant($const)) {
if (!$classDef->extends) {
return false;
}
if (!$this->hasNativeClass($classDef->extends)) {
return false;
}
$classDef = $this->getClassDef($classDef->extends);
} else {
$constDef = $classDef->getConstant($const);
break;
}
}
if (!$this->checkAccessible($classDef, $constDef)) {
$this->fatalError($expr, 'Constant `' . $classDef->getNamespacedName() . '::' . $const . '` is not accessible');
}
if ($constDef->type === self::TYPE_ARRAY) {
return self::PREFIX . $this->getNativeName($constDef->name, $classDef->namespace, $classDef->name);
} else {
return $constDef->value;
}
}
protected function getClassDef(string $name): ClassDef
{
return $this->classes[$this->escapeClass($name)];
@ -3882,18 +3916,14 @@ class CompilerBase extends \PhpAot\Core\Translator
if (($self or $this->isNameExpr($expr->class)) and $this->isIdExpr($expr->name)) {
if ($this->hasNativeClass($class)) {
$classDef = $this->getClassDef($class);
if ($classDef->hasConstant($const)) {
$constInfo = $classDef->getConstant($const);
if ($constInfo->type === self::TYPE_ARRAY) {
return self::PREFIX . $this->getNativeName($constInfo->name, $classDef->namespace, $classDef->name);
} else {
return $constInfo->value;
}
}
if ($classDef->enum) {
$ce = $this->getClassEntryPtr($class);
return 'php::getEnumCase(' . $ce . ', ' . $this->getLiteralString($const) . ')';
}
$nativeConst = $this->getNativeClassConst($expr, $class, $const);
if ($nativeConst) {
return $nativeConst;
}
}
$ce = $this->getClassEntryPtr($class);
return 'php::constant(' . $ce . ', ' . $this->getLiteralString($const) . ')';
@ -4141,7 +4171,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
}
protected function checkAccessible(ClassDef $classDef, MethodDef $methodDef): bool
protected function checkAccessible(ClassDef $classDef, MethodDef|ConstantDef $def): bool
{
// 在当前类中,允许调用所有方法
if ($classDef->namespace === $this->namespace and $classDef->name == $this->class) {
@ -4149,7 +4179,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
// 类外部调用,只允许调用 public 方法
return $methodDef->flags & Modifiers::PUBLIC;
return $def->flags & Modifiers::PUBLIC;
}
protected function findNativeMethod(CallLike $expr, string $object, string $method): string|false

@ -0,0 +1,36 @@
--TEST--
class const 002
--FILE--
<?php
class Worker
{
public const FOO = [
'php',
'java',
'c++',
'golang',
];
}
class Worker2 extends Worker {
}
function main()
{
var_dump(Worker2::FOO);
var_dump(Worker2::FOO[2]);
}
?>
--EXPECT--
array(4) {
[0]=>
string(3) "php"
[1]=>
string(4) "java"
[2]=>
string(3) "c++"
[3]=>
string(6) "golang"
}
string(3) "c++"
Loading…
Cancel
Save