feat(compiler): 添加trait方法参数类名解析功能

- 实现resolveParamClassName方法处理参数类型中的非完全限定类名
- 在parseTrait阶段解析trait方法参数的类名避免gen_stub时上下文丢失
- 支持NullableType和UnionType类型的参数类型解析
- 添加对self、static、parent等特殊类型名称的处理
- 为trait方法参数类名解析功能添加完整的单元测试用例
pull/1/head
韩天峰 2 months ago
parent c7e752422a
commit cd2f4d7ac5
  1. 27
      src/Php/CompilerBase.php
  2. 11
      src/Php/Preprocessor.php
  3. 61
      tests/aot/trait/nullable-class-param.phpt

@ -882,6 +882,33 @@ class CompilerBase extends \PhpAot\Core\Translator
return $class;
}
/**
* 将参数类型中的非完全限定类名解析为完全限定名称。
* 在 parseTrait 阶段调用,避免 gen_stub 时上下文丢失。
*/
protected function resolveParamClassName(?NodeAbstract $type): void
{
if ($type === null) {
return;
}
if ($type instanceof Node\NullableType) {
$this->resolveParamClassName($type->type);
return;
}
if ($type instanceof Node\UnionType) {
foreach ($type->types as $subType) {
$this->resolveParamClassName($subType);
}
return;
}
if ($type instanceof Node\Name && !$type->isFullyQualified()) {
$typeName = $type->toString();
if (!isset($this->zendTypeMap[strtolower($typeName)]) && strtolower($typeName) !== 'self' && strtolower($typeName) !== 'static' && strtolower($typeName) !== 'parent') {
$type->name = '\\' . $this->getNamespacedClassName($typeName);
}
}
}
/**
* 函数名称处理,补齐 namespace
*/

@ -484,6 +484,17 @@ class Preprocessor extends CompilerBase
}
}
// 将 trait 方法参数中的类名解析为完全限定名称,避免 gen_stub 时上下文丢失
if ($class instanceof Node\Stmt\Trait_) {
foreach ($class->stmts as $v) {
if ($v instanceof Node\Stmt\ClassMethod) {
foreach ($v->params as $param) {
$this->resolveParamClassName($param->type);
}
}
}
}
$this->resetClass();
return $code;

@ -0,0 +1,61 @@
--TEST--
Cross-trait call with untyped nullable parameter (regression test for arginfo/zpp mismatch)
--FILE--
<?php
namespace App\Types {
class Node {
public string $name;
public function __construct(string $name = '') {
$this->name = $name;
}
}
}
namespace {
use App\Types\Node;
trait HelperTrait {
// Note: no type hint on $node — ?ClassName on trait methods causes
// arginfo/zpp mismatch between gen_stub.php's ZEND_ARG_OBJ_INFO and
// the AOT compiler's TYPE_VAR-based codegen.
protected function process(string $expr, string $type = '', ?Node $node = null): string {
if ($node instanceof Node) {
return 'node:' . $node->name;
}
if ($type !== '') {
return 'expr:' . $expr . ',type:' . $type;
}
return 'expr:' . $expr;
}
}
trait CallerTrait {
public function runProcess(string $expr, string $type = '', ?Node $node = null): string {
return $this->process($expr, $type, $node);
}
}
class MyProcessor {
use HelperTrait;
use CallerTrait;
}
function main() {
$p = new MyProcessor();
$node = new Node('hello');
var_dump($p->runProcess('data', 'float', $node));
var_dump($p->runProcess('data', 'int'));
var_dump($p->runProcess('data'));
var_dump($p->runProcess('data', 'string', null));
var_dump($p->runProcess('str', 'str', new Node('world')));
}
}
?>
--EXPECT--
string(10) "node:hello"
string(18) "expr:data,type:int"
string(9) "expr:data"
string(21) "expr:data,type:string"
string(10) "node:world"
Loading…
Cancel
Save