fix(php): 修复静态属性访问和操作符映射问题

- 修正 OP_NOT_EMPTY 操作符映射从 '!php::empty' 到 'php::notEmpty'
- 修改 findNativeStaticProperty 方法返回类型从 PropertyDef 到 string
- 添加对 parent:: 静态属性访问的支持和错误处理
- 更新 findNativeProperty 方法参数添加 static 标识符
- 修复静态和动态属性访问的判断逻辑
- 统一错误消息中的对象引用为表达式节点
- 简化静态属性获取的实现逻辑
- 添加静态属性访问的基本功能测试用例
pull/1/head
韩天峰 5 months ago
parent 9af8349762
commit 2267de194b
  1. 49
      src/Php/CompilerBase.php
  2. 16
      tests/aot/basic/static-prop.phpt

@ -3641,7 +3641,7 @@ class CompilerBase extends \PhpAot\Core\Translator
{ {
return match ($op) { return match ($op) {
self::OP_ISSET => 'php::exists', self::OP_ISSET => 'php::exists',
self::OP_NOT_EMPTY => '!php::empty', self::OP_NOT_EMPTY => 'php::notEmpty',
default => 'php::' . $op, default => 'php::' . $op,
}; };
} }
@ -3984,33 +3984,37 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} }
protected function findNativeStaticProperty(Expr\StaticPropertyFetch $expr, ?string &$class): ?PropertyDef protected function findNativeStaticProperty(Expr\StaticPropertyFetch $expr, ?string &$class): ?string
{ {
if ($this->isNameExpr($expr->class) and $this->isIdExpr($expr->name)) { if ($this->isNameExpr($expr->class) and $this->isIdExpr($expr->name)) {
$class = $this->parseIdentifier($expr->class); $class = $this->parseIdentifier($expr->class);
$prop = $this->parseIdentifier($expr->name); $propertyName = $this->parseIdentifier($expr->name);
if ($class === 'self') { if ($class === 'self') {
$class = $this->class; $class = $this->class;
} } elseif ($class === 'parent') {
if (!$this->classDef->extends) {
$fullName = $this->getNamespacedClassName($class); $this->fatalError($expr, 'Cannot access parent:: when current class does not extend any class');
if (!$this->hasClass($fullName)) {
return null;
}
$classDef = $this->getClass($fullName);
if ($classDef->hasProperty($prop)) {
$propDef = $classDef->getProperty($prop);
if ($propDef->isStatic()) {
$class = $fullName;
return $propDef;
} }
$class = $this->classDef->extends;
}
$nativeProperty = $this->findNativeProperty($expr, $propertyName, $class, $this->namespace, true);
if ($nativeProperty) {
$expr->setAttribute('nativeProperty', $nativeProperty);
return $nativeProperty;
} }
} }
return null; return null;
} }
protected function findNativeProperty(NodeAbstract $object, string $property, string $class, string $namespace = ''): ?string /**
* @param NodeAbstract $expr 仅用于输出错误日志
* @param string $property
* @param string $class
* @param string $namespace
* @param bool $static
* @return string|null
*/
protected function findNativeProperty(NodeAbstract $expr, string $property, string $class, string $namespace = '', bool $static = false): ?string
{ {
$findClass = $class; $findClass = $class;
if ($namespace) { if ($namespace) {
@ -4023,8 +4027,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$classDef = $this->getClass($findClass); $classDef = $this->getClass($findClass);
if ($classDef->hasProperty($property)) { if ($classDef->hasProperty($property)) {
$propertyDef = $classDef->getProperty($property); $propertyDef = $classDef->getProperty($property);
// 属性是静态的,但作为动态属性访问,只能动态获取 // 获取动态属性,但找到了静态属性,或者获取静态属性,但是是动态属性,直接返回 null
if ($propertyDef->isStatic()) { if ((!$static and $propertyDef->isStatic()) or ($static and !$propertyDef->isStatic())) {
return null; return null;
} }
if ($propertyDef->isPublic()) { if ($propertyDef->isPublic()) {
@ -4034,12 +4038,12 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($scope) { if ($scope) {
return $this->getPropertyOffset($classDef->getNamespacedName(false), $property); return $this->getPropertyOffset($classDef->getNamespacedName(false), $property);
} }
$this->fatalError($object, "Cannot access protected property `{$property}` of class `{$class}`"); $this->fatalError($expr, "Cannot access protected property `{$property}` of class `{$class}`");
} else { } else {
if ($scope === $findClass) { if ($scope === $findClass) {
return $this->getPropertyOffset($classDef->getNamespacedName(false), $property); return $this->getPropertyOffset($classDef->getNamespacedName(false), $property);
} }
$this->fatalError($object, "Cannot access private property `{$property}` of class `{$class}`"); $this->fatalError($expr, "Cannot access private property `{$property}` of class `{$class}`");
} }
} elseif ($classDef->extends) { } elseif ($classDef->extends) {
$findClass = $classDef->extends; $findClass = $classDef->extends;
@ -4056,8 +4060,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$nativeProp = $this->findNativeStaticProperty($expr, $class); $nativeProp = $this->findNativeStaticProperty($expr, $class);
if ($nativeProp) { if ($nativeProp) {
$classPtr = $this->getClassEntryPtr($class); $classPtr = $this->getClassEntryPtr($class);
$propOffset = $this->getPropertyOffset($class, $nativeProp->name); return 'php::getStaticProperty(' . $classPtr . ', ' . $nativeProp . ')';
return 'php::getStaticProperty(' . $classPtr . ', ' . $propOffset . ')';
} }
return false; return false;
} }

@ -0,0 +1,16 @@
--TEST--
class static
--FILE--
<?php
class Worker
{
public static string $hello;
}
function main()
{
Worker::$hello = "hello";
var_dump(Worker::$hello);
}
?>
--EXPECT--
string(5) "hello"
Loading…
Cancel
Save