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: