From 31a3275ecf19431384e86574f6d1614607b04e83 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Thu, 26 Feb 2026 19:13:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(compiler):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9PH?= =?UTF-8?q?P=E5=BC=95=E7=94=A8=E5=8F=82=E6=95=B0=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在ArgInfo类中新增byRef属性用于标识引用参数 - 重命名parseFunctionDeclaration方法为parseFunctionDecl - 移除引用参数不支持的限制检查 - 在参数解析时添加对byRef的处理逻辑 - 为闭包函数添加引用参数的错误检查 - 在参数类型转换时添加引用参数的特殊处理 - 更新函数调用时参数获取的逻辑以支持引用参数 - 添加引用参数的测试用例 --- src/Php/ArgInfo.php | 1 + src/Php/CompilerBase.php | 47 ++++++++++++++++++++++++----------- src/Php/Preprocessor.php | 2 +- src/Php/Translator.php | 6 ++++- tests/aot/ref-func-param.phpt | 18 ++++++++++++++ 5 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 tests/aot/ref-func-param.phpt diff --git a/src/Php/ArgInfo.php b/src/Php/ArgInfo.php index 87916612..badfde5e 100644 --- a/src/Php/ArgInfo.php +++ b/src/Php/ArgInfo.php @@ -13,5 +13,6 @@ class ArgInfo public string $name; public string $type; public string $default = ''; + public bool $byRef = false; public bool $variadic = false; } diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 23dd7d58..881731af 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -727,7 +727,7 @@ class CompilerBase extends \PhpAot\Core\Translator } } - protected function parseFunctionDeclaration(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): FunctionDef + protected function parseFunctionDecl(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): FunctionDef { // .stub 存根定义 C++ Native 函数,必须设置返回值类型 if (!$v->returnType && $this->stubFile) { @@ -773,7 +773,7 @@ class CompilerBase extends \PhpAot\Core\Translator if (isset($this->nativeFunctions[$name])) { $this->functionDef = $this->nativeFunctions[$name]; } else { - $this->nativeFunctions[$name] = $this->parseFunctionDeclaration($v); + $this->nativeFunctions[$name] = $this->parseFunctionDecl($v); if (isset($this->redoAfterDeclare[$name])) { unset($this->redoAfterDeclare[$name]); $this->climate->cyan('Received redo request, retrying...'); @@ -911,14 +911,12 @@ class CompilerBase extends \PhpAot\Core\Translator $list = []; $functionDef->argCountRequired = count($params); $last = array_key_last($params); + foreach ($params as $i => $param) { // .stub 存根定义 C++ Native 函数,必须设置函数的参数类型 if ($this->stubFile and !$param->type) { throw new \RuntimeException('No type for ' . $this->parseIdentifier($param->var)); } - if ($param->byRef) { - $this->fatalError($param, 'ByRef parameters are not supported'); - } if ($param->variadic and $i !== $last) { $this->fatalError($param, 'Variadic parameters must be the last parameter'); } @@ -932,6 +930,7 @@ class CompilerBase extends \PhpAot\Core\Translator $argInfo = new ArgInfo(); $argInfo->name = $name; $argInfo->type = $type; + $argInfo->byRef = $param->byRef; $argInfo->variadic = $param->variadic; if (isset($param->default)) { $functionDef->argCountRequired = count($list) - 1; @@ -1263,9 +1262,14 @@ class CompilerBase extends \PhpAot\Core\Translator return $str === 'true' || $str === 'false'; } - protected function isNativeType(string $var): bool + protected function isNativeType(string $type): bool { - return in_array($this->getVarType($var), [self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL]); + return in_array($type, [self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL]); + } + + protected function isNativeTypeVar(string $var): bool + { + return $this->isNativeType($this->getVarType($var)); } protected function isInternalFunction(string $fname): bool @@ -1335,7 +1339,7 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->parseBinaryOp($expr->left, $expr->right, '+'); } - protected function parseReturn(mixed $v): string + protected function parseReturn(Node\Stmt\Return_ $v): string { if ($v->expr === null) { if ($this->functionDef->returnType === self::TYPE_VOID and !$this->inClosure) { @@ -1349,10 +1353,10 @@ class CompilerBase extends \PhpAot\Core\Translator $expr = $this->parseExpr($v->expr); // 函数定义时没有声明返回值,但函数体中有返回值,修改为实际的返回值类型 if ($this->getReturnType() === 'void') { - $this->resetReturnType($type); - } elseif ($this->getReturnType() !== self::TYPE_VAR and $this->getReturnType() !== $type) { + $this->resetReturnType($v, $type); + } elseif ($this->isNativeType($type) and $this->getReturnType() !== self::TYPE_VAR and $this->getReturnType() !== $type) { // 返回值类型不一致,说明存在多种类型的返回值,修改为 var 表示 any - $this->resetReturnType(self::TYPE_VAR); + $this->resetReturnType($v, self::TYPE_VAR); } $exprCode = $this->convertExprType($expr, $this->getReturnType(), $type); // return 如果使用了 Indirect 语句,可能会导致变量提前析构,出现悬空指针 @@ -1442,11 +1446,11 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->classes[$this->escapeClass($name)]; } - protected function resetReturnType(string $type): void + protected function resetReturnType(Node\Stmt\Return_ $node, string $type): void { $this->functionDef->returnType = $type; // 返回值变更,需要重新解析 - $this->climate->cyan('Return type changed, retrying...'); + $this->climate->cyan('Return type changed at line ' . $node->getLine() . ', retrying...'); throw new Redo(); } @@ -1562,6 +1566,9 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseParameterType(Node\Param $param, string $var): string { + if ($param->byRef) { + return self::TYPE_REF; + } $type = $param->type; if ($type == null) { return self::TYPE_VAR; @@ -2713,11 +2720,15 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->functionDef->returnType; } - protected function getTypeConvertedArg($arg, $argInfo): string + protected function getTypeConvertedArg($arg, ArgInfo $argInfo): string { $expr = $this->parseArg($arg); $type = $this->detectExprType($arg->value); + if ($argInfo->byRef) { + return $this->convertToRef($arg->value); + } + return $this->convertExprType($expr, $argInfo->type, $type); } @@ -3210,7 +3221,7 @@ class CompilerBase extends \PhpAot\Core\Translator { $this->checkLeftValue($expr); $var = $this->parseIdentifier($expr); - if ($this->isVarExpr($expr) and $this->isNativeType($var)) { + if ($this->isVarExpr($expr) and $this->isNativeTypeVar($var)) { $this->localVars[$var] = self::TYPE_VAR; } return $this->parseIdentifier($expr) . '.toReference()'; @@ -3848,6 +3859,9 @@ class CompilerBase extends \PhpAot\Core\Translator $this->indentLevel++; foreach ($expr->params as $i => $param) { + if ($param->byRef) { + $this->fatalError($expr, 'Closure cannot use reference parameter'); + } $var = $this->parseIdentifier($param->var); $fnCode .= 'auto ' . $var . ' = php::getCallArg(' . $i . ');' . PHP_EOL; $this->addArgument($var, self::TYPE_VAR); @@ -3895,6 +3909,9 @@ class CompilerBase extends \PhpAot\Core\Translator $fnBodyCode = ''; foreach ($expr->params as $i => $param) { + if ($param->byRef) { + $this->fatalError($expr, 'Closure cannot use reference parameter'); + } $var = $this->parseIdentifier($param->var); $fnBodyCode .= 'auto ' . $var . ' = php::getCallArg(' . $i . ');' . PHP_EOL; $this->addArgument($var, self::TYPE_VAR); diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index 7c01894a..556d9fe8 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -159,7 +159,7 @@ class Preprocessor extends CompilerBase { $name = $this->getFunctionName($v); if ($this->stubFile) { - $this->nativeFunctions[$name] = $this->parseFunctionDeclaration($v); + $this->nativeFunctions[$name] = $this->parseFunctionDecl($v); } else { $this->functionDeclInFile[$name] = $this->file; } diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 525093ce..1acedf43 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -755,7 +755,11 @@ class Translator extends Preprocessor if ($argInfo->default) { $argExpr = 'php::getCallArg(' . $k . ', ' . $argInfo->default . ')'; } else { - $argExpr = 'php::getCallArg(' . $k . ')'; + if ($argInfo->byRef) { + $argExpr = 'php::getCallArgByRef(' . $k . ')'; + } else { + $argExpr = 'php::getCallArg(' . $k . ')'; + } } $expr = $this->convertExprFromType($argInfo->type, $argExpr); $cppCode .= $this->getIndent() . $argInfo->type . ' ' . $var . ' = ' . $expr . ';' . PHP_EOL; diff --git a/tests/aot/ref-func-param.phpt b/tests/aot/ref-func-param.phpt new file mode 100644 index 00000000..a30aefa8 --- /dev/null +++ b/tests/aot/ref-func-param.phpt @@ -0,0 +1,18 @@ +--TEST-- +Ref function parameter +--FILE-- + +--EXPECT-- +string(7) "foo bar"