From 928f9050d6ef0c072665379be311d946148e1078 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Mon, 25 May 2026 12:46:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9PHP?= =?UTF-8?q?=E5=B8=B8=E9=87=8F=E5=92=8C=E5=88=86=E7=BB=84use=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增useConstants数组用于存储常量导入映射 - 实现常量名称解析和命名空间查找逻辑 - 支持通过别名导入常量的功能 - 添加对分组use语句的解析处理 - 完善匿名类继承接口的全限定名称转换 - 优化函数调用时的参数信息获取方式 - 修复方法调用中本地函数定义的引用方式 --- src/Php/CompilerBase.php | 67 ++++++++++++++++++++++++++++++++++------ src/Php/Preprocessor.php | 6 ++++ src/Php/Translator.php | 6 ++++ 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 5b136f6c..5094cde8 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -203,6 +203,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected array $useNamespaces = []; protected array $useAliases = []; protected array $useFunctions = []; + protected array $useConstants = []; /** * 原始类名,不包含命名空间. @@ -817,6 +818,7 @@ class CompilerBase extends \PhpAot\Core\Translator $this->useNamespaces = []; $this->useAliases = []; $this->useFunctions = []; + $this->useConstants = []; $this->namespace = ''; } @@ -2248,7 +2250,7 @@ class CompilerBase extends \PhpAot\Core\Translator $method = $this->parseIdentifier($expr->name); $nativeFunc = $this->findNativeMethod($expr, $object, $method); if ($nativeFunc) { - $funcDef = $this->functions[$nativeFunc]; + $funcDef = $this->getFunction($nativeFunc); return $funcDef->returnType; } if ($this->isTypedObject($object)) { @@ -2989,10 +2991,10 @@ class CompilerBase extends \PhpAot\Core\Translator $possibleFunctionNames[] = $this->escapeName($this->escapeNamespace($this->useAliases[$funcName])); } if ($this->namespace) { - $possibleFunctionNames[] = $this->escapeNamespace($this->namespace) . self::NAMESPACE_SEPARATOR . $funcName; + $possibleFunctionNames[] = $this->escapeNamespace($this->namespace) . self::NAMESPACE_SEPARATOR . $this->escapeName($funcName); } if (isset($this->useFunctions[$funcName])) { - $possibleFunctionNames[] = $this->escapeNamespace($this->useFunctions[$funcName]) . self::NAMESPACE_SEPARATOR . $funcName; + $possibleFunctionNames[] = $this->escapeNamespace($this->useFunctions[$funcName]) . self::NAMESPACE_SEPARATOR . $this->escapeName($funcName); } // 复杂命名空间规则,组合命名空间 // 例子:use foo\bar; bar\fn(); @@ -3078,7 +3080,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseNativeCallArgs(array $callArgs, string $nativeFunc): string { $argList = []; - $functionDef = $this->functions[$nativeFunc]; + $functionDef = $this->getFunction($nativeFunc); $args = []; $hasNamedArg = false; // 对命名参数进行重排 @@ -3731,12 +3733,18 @@ class CompilerBase extends \PhpAot\Core\Translator $classDef = $expr->class; $className = $this->genAnonClassName(); $classDef->name = new Node\Identifier($className); - // 继承父类可能是 use 的名称,需要转换成全限定名称 + // 继承父类和接口可能是 use 的名称,需要转换成全限定名称 // TODO 匿名类的属性、常量、方法参数中都可能会用相对类名,都需要转为全限定名称 if ($classDef->extends !== null) { $parentClass = $this->getNamespacedClassName($classDef->extends->toString()); $classDef->extends = new Node\Name\FullyQualified($parentClass); } + if (!empty($classDef->implements)) { + foreach ($classDef->implements as $i => $iface) { + $ifaceName = $this->getNamespacedClassName($iface->toString()); + $classDef->implements[$i] = new Node\Name\FullyQualified($ifaceName); + } + } $this->context->beforeStmtLines[] = 'static THREAD_LOCAL bool ' . $className . '_defined = false;'; $classCode = $this->genEmbeddedCode($classDef); $this->addConstData($className . '_code', $classCode); @@ -3822,9 +3830,22 @@ class CompilerBase extends \PhpAot\Core\Translator abort($expr); } $name = $this->parseIdentifier($expr->name); + $name = ltrim($name, '\\'); if ($this->isNameExpr($expr->name) and $this->hasConstant($name)) { return $this->getConstant($name); } + if ($this->namespace and $this->isNameExpr($expr->name) and !str_contains($name, '\\')) { + $nsName = $this->namespace . '\\' . $name; + if ($this->hasConstant($nsName)) { + return $this->getConstant($nsName); + } + } + if ($this->isNameExpr($expr->name) and isset($this->useConstants[$name])) { + $importedName = $this->useConstants[$name]; + if ($this->hasConstant($importedName)) { + return $this->getConstant($importedName); + } + } if ($name === 'null') { return self::VALUE_NULL; } @@ -3852,6 +3873,8 @@ class CompilerBase extends \PhpAot\Core\Translator } if (isset($this->useAliases[$name])) { $name = $this->useAliases[$name]; + } elseif (isset($this->useConstants[$name])) { + $name = $this->useConstants[$name]; } else { $fullName = $this->getNamespacedClassName($name); if ($fullName) { @@ -3920,10 +3943,10 @@ class CompilerBase extends \PhpAot\Core\Translator protected function getArgInfo(Node $arg, string $funcName, int $index): ArgInfo { - if (!isset($this->functions[$funcName])) { + if (!$this->hasFunction($funcName)) { $this->fatalError($arg, "Function `{$funcName}` is undefined, you must adjust the order of function definition"); } - $funcDef = $this->functions[$funcName]; + $funcDef = $this->getFunction($funcName); if (!array_key_exists($index, $funcDef->argInfoList)) { $this->fatalError($arg, "Argument `{$index}` of function `{$funcName}` not found"); } @@ -5323,7 +5346,21 @@ class CompilerBase extends \PhpAot\Core\Translator $lastIndex = strrpos($id, '\\'); $fn = substr($id, $lastIndex + 1); $ns = substr($id, 0, $lastIndex); - $this->useFunctions[$fn] = $ns; + if ($use->alias) { + $this->useFunctions[$use->alias->toString()] = $ns; + } else { + $this->useFunctions[$fn] = $ns; + } + } elseif ($type === Node\Stmt\Use_::TYPE_CONSTANT) { + $lastIndex = strrpos($id, '\\'); + $cn = substr($id, $lastIndex + 1); + $ns = substr($id, 0, $lastIndex); + $fullName = $ns . '\\' . $cn; + if ($use->alias) { + $this->useConstants[$use->alias->toString()] = $fullName; + } else { + $this->useConstants[$cn] = $fullName; + } } else { if ($id === 'native_types') { $this->nativeTypes = true; @@ -5338,6 +5375,18 @@ class CompilerBase extends \PhpAot\Core\Translator return $code; } + protected function parseGroupUse(Node\Stmt\GroupUse $node): void + { + $prefix = $node->prefix; + $uses = []; + foreach ($node->uses as $use) { + $fullName = Node\Name::concat($prefix, $use->name); + $uses[] = new Node\UseItem($fullName, $use->alias, $use->type); + } + $syntheticUse = new Node\Stmt\Use_($uses, $node->type); + $this->parseUse($syntheticUse); + } + protected function parseErrorSuppress(Expr\ErrorSuppress $expr): string { $tmpVar = $this->genTmpVarName(); @@ -5680,7 +5729,7 @@ class CompilerBase extends \PhpAot\Core\Translator } if ($this->isCallExpr($expr->expr)) { $nativeCall = $expr->expr->getAttribute('nativeCall'); - if ($nativeCall and $this->functions[$nativeCall]->returnType === self::TYPE_VOID) { + if ($nativeCall and $this->getFunction($nativeCall)->returnType === self::TYPE_VOID) { return $beforeCode . PHP_EOL . $code . ';' . PHP_EOL . 'return ' . self::VALUE_NULL . ';'; } } diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index c6cd36a6..164472ea 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -148,6 +148,9 @@ class Preprocessor extends CompilerBase case 'Stmt_Use': $this->parseUse($v); break; + case 'Stmt_GroupUse': + $this->parseGroupUse($v); + break; case 'Stmt_Declare': case 'Stmt_Nop': break; @@ -220,6 +223,9 @@ class Preprocessor extends CompilerBase case 'Stmt_Use': $this->parseUse($v2); break; + case 'Stmt_GroupUse': + $this->parseGroupUse($v2); + break; case 'Stmt_Const': break; case 'Stmt_Interface': diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 4fb80406..d89eeb53 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -1470,6 +1470,9 @@ CODE; case 'Stmt_Use': $cppCode .= $this->parseUse($v) . PHP_EOL; break; + case 'Stmt_GroupUse': + $this->parseGroupUse($v); + break; case 'Stmt_Function': $cppCode .= $this->parseFunction($v) . PHP_EOL; break; @@ -1609,6 +1612,9 @@ CODE; case 'Stmt_Use': $code .= $this->parseUse($v2) . PHP_EOL; break; + case 'Stmt_GroupUse': + $this->parseGroupUse($v2); + break; case 'Stmt_Interface': break; default: