fix(php): 修复编译器中的命名空间处理和常量解析问题

- 修正 getNativeName 方法中命名数组构建逻辑,确保函数名正确添加到数组中
- 限制函数参数默认值只支持字面量,防止使用表达式获取值导致的问题
- 优化返回值处理逻辑,将 return 语句移至 afterStmtLines 队列确保内存安全
- 修改 parseConstFetch 方法签名,添加 scalar 参数控制常量解析行为
- 为函数参数信息添加类型注释提升代码可读性
pull/1/head
韩天峰 6 months ago
parent a0d750eea0
commit 15ea7023f0
  1. 27
      src/Php/CompilerBase.php
  2. 3
      src/Php/Translator.php

@ -670,15 +670,14 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function getNativeName(string $fn, string $ns = '', string $class = ''): string
{
$names[] = $this->escapeName($fn);
if ($ns) {
$names[] = $this->escapeNamespace($ns);
}
if ($class) {
$names[] = $this->escapeClass($class);
}
return implode(self::NAMESPACE_SEPARATOR, array_reverse($names));
$names[] = $this->escapeName($fn);
return implode(self::NAMESPACE_SEPARATOR, $names);
}
protected function getClassId(string $className): int
@ -942,7 +941,14 @@ class CompilerBase extends \PhpAot\Core\Translator
$argInfo->variadic = $param->variadic;
if (isset($param->default)) {
$functionDef->argCountRequired = count($list) - 1;
$argInfo->default = $this->parseIdentifier($param->default);
/**
* 函数参数默认值只能为字面量,无法使用表达式获取值
*/
if ($param->default instanceof Node\Expr\ConstFetch) {
$argInfo->default = $this->parseConstFetch($param->default, true);
} else {
$argInfo->default = $this->parseIdentifier($param->default);
}
}
$functionDef->argInfoList[] = $argInfo;
}
@ -1367,15 +1373,17 @@ class CompilerBase extends \PhpAot\Core\Translator
// 返回值类型不一致,说明存在多种类型的返回值,修改为 var 表示 any
$this->resetReturnType($v, self::TYPE_VAR);
}
$exprCode = $this->convertExprType($expr, $this->getReturnType(), $type);
$returnType = $this->getReturnType();
$exprCode = $this->convertExprType($expr, $returnType, $type);
// return 如果使用了 Indirect 语句,可能会导致变量提前析构,出现悬空指针
// 将 Indirect 赋值给临时变量后,使用 Ctor::Copy 解除了 Indirect,保证内存安全
if (!$this->isVarExpr($v->expr) and !$this->isScalar($v->expr)) {
$tmpVar = $this->genTmpVarName();
// 必须提前声明变量,否则在末尾声明并 return 可能会被 gcc 优化掉
$this->addLocalVar($tmpVar, $type);
$this->addLocalVar($tmpVar, $returnType);
$code = $tmpVar . ' = ' . $exprCode . ';' . PHP_EOL;
$code .= $this->getIndent() . 'return ' . $tmpVar . ';';
// 解析表达式后可能会插入语句,因此需要在末尾添加 return 语句,而不是直接返回
$this->afterStmtLines[] = $this->getIndent() . 'return ' . $tmpVar . ';';
} else {
$code = 'return ' . $exprCode . ';';
}
@ -2593,7 +2601,7 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->convertObjectExpr($this->parseExpr($node->expr));
}
protected function parseConstFetch(Node\Expr\ConstFetch $expr): string
protected function parseConstFetch(Node\Expr\ConstFetch $expr, bool $scalar = false): string
{
if ($expr->name->getType() != 'Name' and !($expr->name instanceof Node\Name\FullyQualified)) {
abort($expr);
@ -2614,6 +2622,9 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($name === 'PHP_EOL') {
return '"' . $this->escapeString(PHP_EOL) . '"';
}
if ($scalar) {
return constant($expr->name);
}
if ($this->isNameExpr($expr->name)) {
if (str_contains($name, '::')) {
$ns = explode('::', $name)[0];

@ -307,6 +307,9 @@ class Translator extends Preprocessor
}
$argInfoList = $func->argInfoList;
if ($argInfoList) {
/**
* @var ArgInfo $argInfo
*/
foreach ($argInfoList as $argInfo) {
if ($argInfo->variadic) {
$arg = self::TYPE_ARRAY . ' ' . $argInfo->name . '()';

Loading…
Cancel
Save