feat(php): 支持trait方法别名和访问修饰符转换

- 修改traitAliases数据结构以存储方法别名和新修饰符信息
- 实现trait方法别名时保留原始访问修饰符功能
- 添加对trait方法别名中newModifier属性的支持
- 更新翻译器中trait方法别名处理逻辑
- 扩展测试用例验证trait方法冲突解决机制
pull/1/head
韩天峰 5 months ago
parent 57220d63b9
commit aea979fae1
  1. 2
      src/Php/Entity/ClassDef.php
  2. 8
      src/Php/Preprocessor.php
  3. 14
      src/Php/Translator.php
  4. 35
      tests/aot/trait/005.phpt

@ -34,7 +34,7 @@ class ClassDef extends ClassLikeDef
public ?Trait_ $trait = null; public ?Trait_ $trait = null;
/** /**
* FullMethodName -> NewMethodName * FullMethodName -> NewMethodName
* @var array<string, string> * @var array<string, array>
*/ */
public array $traitAliases = []; public array $traitAliases = [];
/** /**

@ -616,15 +616,15 @@ class Preprocessor extends CompilerBase
if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Alias) { if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Alias) {
$trait1 = $this->getNamespacedClassName($adaptation->trait); $trait1 = $this->getNamespacedClassName($adaptation->trait);
$methodName = $adaptation->method->toString(); $methodName = $adaptation->method->toString();
if ($adaptation->newModifier) {
$this->fatalError($traitUse, "Trait `{$trait1}` cannot use `newModifier`");
}
/** /**
* 例如: * 例如:
* use TraitA { TraitA::method as newMethod} * use TraitA { TraitA::method as newMethod}
* 这表示 TraitA::method() 会被重命名为 TraitA::newMethod() * 这表示 TraitA::method() 会被重命名为 TraitA::newMethod()
*/ */
$aliases[$this->getFullMethodName($trait1, $methodName)] = $adaptation->newName->toString(); $aliases[$this->getFullMethodName($trait1, $methodName)] = array(
'newName' => $adaptation->newName->toString(),
'newModifier' => $adaptation->newModifier ?: $adaptation->newModifier->toString(),
);
} }
if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Precedence) { if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Precedence) {
$methodName = $adaptation->method->toString(); $methodName = $adaptation->method->toString();

@ -972,8 +972,11 @@ class Translator extends Preprocessor
$fullMethodName = $this->getFullMethodName($traitFullName, $methodName); $fullMethodName = $this->getFullMethodName($traitFullName, $methodName);
if (isset($classDef->traitAliases[$fullMethodName])) { if (isset($classDef->traitAliases[$fullMethodName])) {
$alias = $classDef->traitAliases[$fullMethodName]; $alias = $classDef->traitAliases[$fullMethodName];
$traitStmt->name = new Node\Identifier($alias); $methodName = $alias['newName'];
$methodName = $alias; $traitStmt->name = new Node\Identifier($methodName);
if ($alias['newModifier']) {
$traitStmt->flags = $alias['newModifier'];
}
} }
if (isset($classDef->traitIgnored[$fullMethodName])) { if (isset($classDef->traitIgnored[$fullMethodName])) {
unset($traitStmts[$k1]); unset($traitStmts[$k1]);
@ -1296,9 +1299,12 @@ class Translator extends Preprocessor
$fullMethodName = $this->getFullMethodName($traitFullName, $traitMethodName); $fullMethodName = $this->getFullMethodName($traitFullName, $traitMethodName);
// Trait 设置了别名 // Trait 设置了别名
if (isset($classDef->traitAliases[$fullMethodName])) { if (isset($classDef->traitAliases[$fullMethodName])) {
$classMethodName = $classDef->traitAliases[$fullMethodName]; $alias = $classDef->traitAliases[$fullMethodName];
$methodDef = clone $methodDef; $methodDef = clone $methodDef;
$methodDef->name = $classMethodName; $classMethodName = $methodDef->name = $alias['newName'];
if ($alias['newModifier']) {
$methodDef->flags = $this->parseModifiers($alias['newModifier']);
}
} }
// 设置了 insteadof 选项,此 Trait 的方法将不会被使用 // 设置了 insteadof 选项,此 Trait 的方法将不会被使用
if (isset($classDef->traitIgnored[$fullMethodName])) { if (isset($classDef->traitIgnored[$fullMethodName])) {

@ -0,0 +1,35 @@
--TEST--
Method conflict in traits
--FILE--
<?php
trait THello1
{
private function hello()
{
echo 'Hello 2', PHP_EOL;
}
}
class TraitsTest
{
use THello1 {
THello1::hello as public hello2;
}
public function hello()
{
echo 'Hello 1' , PHP_EOL;
}
}
function main()
{
$o = new TraitsTest;
$o->hello2();
$o->hello();
}
?>
--EXPECT--
Hello 2
Hello 1
Loading…
Cancel
Save