feat(php): 添加对PHP常量和分组use语句的支持

- 新增useConstants数组用于存储常量导入映射
- 实现常量名称解析和命名空间查找逻辑
- 支持通过别名导入常量的功能
- 添加对分组use语句的解析处理
- 完善匿名类继承接口的全限定名称转换
- 优化函数调用时的参数信息获取方式
- 修复方法调用中本地函数定义的引用方式
pull/1/head
韩天峰 3 months ago
parent b11a6630fe
commit 928f9050d6
  1. 67
      src/Php/CompilerBase.php
  2. 6
      src/Php/Preprocessor.php
  3. 6
      src/Php/Translator.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 . ';';
}
}

@ -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':

@ -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:

Loading…
Cancel
Save