fix(trait): 修复trait方法冲突处理问题

- 添加trait别名功能支持
- 修复trait使用语法错误提示信息
- 更新trait方法命名规则避免冲突
- 添加trait方法调用前缀处理
- 优化trait适应性代码结构
- 修复trait方法重写逻辑
pull/1/head
韩天峰 4 months ago
parent aea979fae1
commit 1658dc2bfa
  1. 2
      src/Php/Entity/ClassDef.php
  2. 10
      src/Php/Preprocessor.php
  3. 10
      src/Php/Translator.php
  4. 24
      tests/aot/trait/006.phpt

@ -32,11 +32,13 @@ class ClassDef extends ClassLikeDef
public bool $requireCtor = false;
public bool $enum = false;
public ?Trait_ $trait = null;
/**
* FullMethodName -> NewMethodName
* @var array<string, array>
*/
public array $traitAliases = [];
/**
* FullMethodName -> true
* @var array<string, bool>

@ -611,24 +611,24 @@ class Preprocessor extends CompilerBase
{
foreach ($traitUse->adaptations as $adaptation) {
if (!$adaptation->trait) {
$this->fatalError($traitUse, "Trait `use` cannot use `use` without `as`");
$this->fatalError($traitUse, 'Trait `use` cannot use `use` without `as`');
}
if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Alias) {
$trait1 = $this->getNamespacedClassName($adaptation->trait);
$methodName = $adaptation->method->toString();
/**
/*
* 例如:
* use TraitA { TraitA::method as newMethod}
* 这表示 TraitA::method() 会被重命名为 TraitA::newMethod()
*/
$aliases[$this->getFullMethodName($trait1, $methodName)] = array(
$aliases[$this->getFullMethodName($trait1, $methodName)] = [
'newName' => $adaptation->newName->toString(),
'newModifier' => $adaptation->newModifier ?: $adaptation->newModifier->toString(),
);
];
}
if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Precedence) {
$methodName = $adaptation->method->toString();
/**
/*
* 例如:
* use TraitA { TraitA::method insteadof TraitB}
* 这表示 TraitB::method() 将会被忽略,真正执行的是 TraitA::method()

@ -1316,15 +1316,15 @@ class Translator extends Preprocessor
}
$classDef->addMethod($methodDef);
$traitMethodNativeName = self::PREFIX . $this->getNativeName($traitMethodName, $traitDef->namespace, $traitDef->name);
$classMethodNativeName = self::PREFIX . $this->getNativeName($classMethodName, $classDef->namespace, $classDef->name);
$traitMethodNativeName = $this->getNativeName($traitMethodName, $traitDef->namespace, $traitDef->name);
$classMethodNativeName = $this->getNativeName($classMethodName, $classDef->namespace, $classDef->name);
$argList = ['this_'];
foreach ($methodDef->functionDef->argInfoList as $argInfo) {
$argList[] = $argInfo->name;
}
$argv = implode(', ', $argList);
$code = $methodDef->getReturnType() . ' ' . $classMethodNativeName . '(';
$code = $methodDef->getReturnType() . ' ' . self::PREFIX . $classMethodNativeName . '(';
if ($this->class) {
$code .= self::TYPE_OBJECT . ' &this_';
if ($methodDef->functionDef->params) {
@ -1332,10 +1332,12 @@ class Translator extends Preprocessor
}
}
$this->addFunction($classMethodNativeName, $methodDef->functionDef);
$code .= $methodDef->functionDef->params . ')';
$code .= '{' . PHP_EOL;
$this->indentLevel++;
$methodCall = $traitMethodNativeName . '(' . $argv . ')';
$methodCall = self::PREFIX . $traitMethodNativeName . '(' . $argv . ')';
if ($methodDef->getReturnType() !== self::TYPE_VOID) {
$methodCall = 'return ' . $methodCall;
}

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