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

- 添加trait别名功能支持
- 修复trait使用语法错误提示信息
- 更新trait方法命名规则避免冲突
- 添加trait方法调用前缀处理
- 优化trait适应性代码结构
- 修复trait方法重写逻辑
pull/1/head
韩天峰 5 months ago
parent aea979fae1
commit 1658dc2bfa
  1. 2
      src/Php/Entity/ClassDef.php
  2. 12
      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 $requireCtor = false;
public bool $enum = false; public bool $enum = false;
public ?Trait_ $trait = null; public ?Trait_ $trait = null;
/** /**
* FullMethodName -> NewMethodName * FullMethodName -> NewMethodName
* @var array<string, array> * @var array<string, array>
*/ */
public array $traitAliases = []; public array $traitAliases = [];
/** /**
* FullMethodName -> true * FullMethodName -> true
* @var array<string, bool> * @var array<string, bool>

@ -611,29 +611,29 @@ class Preprocessor extends CompilerBase
{ {
foreach ($traitUse->adaptations as $adaptation) { foreach ($traitUse->adaptations as $adaptation) {
if (!$adaptation->trait) { 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) { 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();
/** /*
* 例如: * 例如:
* 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)] = array( $aliases[$this->getFullMethodName($trait1, $methodName)] = [
'newName' => $adaptation->newName->toString(), 'newName' => $adaptation->newName->toString(),
'newModifier' => $adaptation->newModifier ?: $adaptation->newModifier->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();
/** /*
* 例如: * 例如:
* use TraitA { TraitA::method insteadof TraitB} * use TraitA { TraitA::method insteadof TraitB}
* 这表示 TraitB::method() 将会被忽略,真正执行的是 TraitA::method() * 这表示 TraitB::method() 将会被忽略,真正执行的是 TraitA::method()
*/ */
foreach($adaptation->insteadof as $trait2) { foreach ($adaptation->insteadof as $trait2) {
$ignored[$this->getFullMethodName($trait2, $methodName)] = true; $ignored[$this->getFullMethodName($trait2, $methodName)] = true;
} }
} }

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