fix(php): 修复类常量解析和对象转换功能

- 添加对 self::class、parent::class 和 static::class 的支持
- 实现 parent::class 的继承链验证和错误处理
- 禁止使用 static::class 并提示编译时无法解析
- 移除 objval() 函数中的冗余参数验证逻辑
- 为 self::class 和 parent::class 场景添加测试用例
- 更新版本号至 1064
- 添加 yield 示例代码文件
pull/1/head
韩天峰 3 months ago
parent d082de3f6e
commit 0647b6425a
  1. 10
      examples/fn.php
  2. 8
      examples/yield.php
  3. 21
      src/Php/CompilerBase.php
  4. 24
      tests/aot/class/objval-2.phpt
  5. 32
      tests/aot/class/objval-parent.phpt
  6. 2
      version.txt

@ -0,0 +1,10 @@
<?php
function fn_test_yeild()
{
echo "第一次调用前\n";
yield 1; // 产生值 1,并暂停
echo "两次调用之间\n";
yield 2; // 产生值 2,并暂停
echo "最后一次调用后\n";
yield 3;
}

@ -0,0 +1,8 @@
<?php
function main()
{
require __DIR__ . '/fn.php';
var_dump(fn_test_yeild());
}

@ -1471,10 +1471,21 @@ class CompilerBase extends \PhpAot\Core\Translator
}
if ($this->isClassConstFetch($arg)) {
if ($this->isNameExpr($arg->class) and $this->isIdExpr($arg->name) and $this->parseIdentifier($arg->name) === 'class') {
return $this->getNamespacedClassName($this->parseIdentifier($arg->class));
$class = $this->parseIdentifier($arg->class);
if ($class === 'self') {
$class = $this->class;
} elseif ($class === 'parent') {
if (!$this->classDef || !$this->classDef->extends) {
$this->fatalError($arg, 'Cannot use "parent" outside a class or class does not extend any class');
}
return $this->classDef->extends;
} elseif ($class === 'static') {
$this->fatalError($arg, "'static::class' cannot be resolved at compile time, use a concrete class name or 'self::class'");
}
return '';
return $this->getNamespacedClassName($class);
}
}
$this->fatalError($arg, 'Only string literals or `ClassName::class` constant are supported');
}
protected function parseReturn(Node\Stmt\Return_ $v): string
@ -4329,9 +4340,6 @@ class CompilerBase extends \PhpAot\Core\Translator
}
$receiver = $this->parseExpr($expr->args[0]->value);
$className = $this->resolveClassNameArg($expr->args[1]->value);
if ($className === '') {
$this->fatalError($expr, 'The second parameter of objval() only supports string literals or `ClassName::class` constant');
}
return 'php::toObject(' . $receiver . ', ' . $this->getClassEntryPtr($className) . ', true)';
}
@ -4341,9 +4349,6 @@ class CompilerBase extends \PhpAot\Core\Translator
return 'php::toObject(' . $receiver . ')';
}
$className = $this->resolveClassNameArg($expr->args[0]->value);
if ($className === '') {
$this->fatalError($expr, 'The first parameter of toObject() only supports string literals or `ClassName::class` constant');
}
return 'php::toObject(' . $receiver . ', ' . $this->getClassEntryPtr($className) . ', true)';
}

@ -0,0 +1,24 @@
--TEST--
objval
--FILE--
<?php
class Foo {
public function run($obj) {
$o = objval($obj, self::class);
$o->bar();
}
public function bar() {
var_dump(__METHOD__);
}
}
function main() {
$o = new Foo();
$o->run($o);
}
?>
--EXPECT--
string(8) "Foo::bar"

@ -0,0 +1,32 @@
--TEST--
objval with parent::class
--FILE--
<?php
class Base {
public function name(): string {
return 'Base';
}
}
class Child extends Base {
public function name(): string {
return 'Child';
}
public function castToParent($obj): Base {
return objval($obj, parent::class);
}
}
function main() {
$b = new Base();
$c = new Child();
$result = $c->castToParent($b);
var_dump($result->name());
}
?>
--EXPECT--
string(4) "Base"

@ -1 +1 @@
1063
1064

Loading…
Cancel
Save