From 8670df2a3e466ba0b2bb080f9937289cc58fab6a Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Thu, 2 Apr 2026 12:02:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(php):=20=E8=A7=A3=E5=86=B3=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E8=BF=94=E5=9B=9E=E5=BC=95=E7=94=A8=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加对函数返回引用类型的检查,禁止返回引用类型 - 修复赋值引用表达式的解析逻辑,确保左侧为变量 - 添加临时变量处理非变量表达式的引用赋值 - 新增函数返回引用的测试用例验证错误处理 --- phpunit/code/function-return-ref.php | 15 +++++++ phpunit/src/FunctionTest.php | 9 +++++ src/Php/CompilerBase.php | 59 ++++++++++++++++------------ 3 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 phpunit/code/function-return-ref.php create mode 100644 phpunit/src/FunctionTest.php diff --git a/phpunit/code/function-return-ref.php b/phpunit/code/function-return-ref.php new file mode 100644 index 00000000..0e985734 --- /dev/null +++ b/phpunit/code/function-return-ref.php @@ -0,0 +1,15 @@ +exec('The return type of the function `test` cannot be a reference type', 'function-return-ref.php'); + } +} diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 5497dfe3..b96b4263 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -794,7 +794,11 @@ class CompilerBase extends \PhpAot\Core\Translator { // .stub 存根定义 C++ Native 函数,必须设置返回值类型 if (!$v->returnType && $this->stubFile) { - throw new \Exception('No return type for ' . $v->name); + $this->fatalError($v, 'The return type of the function `' . $v->name . '` must be specified'); + } + // 返回值不能是引用类型 + if ($v->byRef) { + $this->fatalError($v, 'The return type of the function `' . $v->name . '` cannot be a reference type'); } $fnName = $this->parseIdentifier($v->name); @@ -3739,33 +3743,38 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseAssignRef(Node\Expr\AssignRef $expr): string { - if ($this->isVarExpr($expr->var)) { - $this->context->inAssignExpr = true; - $left = $this->parseIdentifier($expr->var); - $this->context->inAssignExpr = false; - if (!$this->hasVar($left)) { - $this->addLocalVar($left, self::TYPE_REF); - } else { - $type = $this->getVarType($left); - if ($type !== self::TYPE_REF) { - $this->fatalError($expr, 'Cannot assign reference to variable of type ' . $type); - } - } - if ($this->isVarExpr($expr->expr)) { - return $left . ' = ' . $this->parseIdentifier($expr->expr) . '.toReference()'; - } - if ($expr->expr->getType() === self::EXPR_ARRAY_DIM_FETCH) { - return $left . ' = ' . $this->parseIdentifier($expr->expr); - } - if ($this->isPropertyFetch($expr->expr)) { - $left = $this->parseIdentifier($expr->var); - $object = $this->parseExpr($expr->expr->var); - $prop = $this->identifierToStr($expr->expr->name); + if (!$this->isVarExpr($expr->var)) { + $this->fatalError($expr, 'Cannot assign reference to non-variable'); + } - return $left . ' = ' . $object . '.attrRef(' . $prop . ')'; + $this->context->inAssignExpr = true; + $left = $this->parseIdentifier($expr->var); + $this->context->inAssignExpr = false; + if (!$this->hasVar($left)) { + $this->addLocalVar($left, self::TYPE_REF); + } else { + $type = $this->getVarType($left); + if ($type !== self::TYPE_REF) { + $this->fatalError($expr, 'Cannot assign reference to variable of type ' . $type); } } - $this->fatalError($expr, 'Cannot assign reference to non-variable'); + if ($this->isVarExpr($expr->expr)) { + return $left . ' = ' . $this->parseIdentifier($expr->expr) . '.toReference()'; + } + if ($expr->expr->getType() === self::EXPR_ARRAY_DIM_FETCH) { + return $left . ' = ' . $this->parseIdentifier($expr->expr); + } + if ($this->isPropertyFetch($expr->expr)) { + $left = $this->parseIdentifier($expr->var); + $object = $this->parseExpr($expr->expr->var); + $prop = $this->identifierToStr($expr->expr->name); + + return $left . ' = ' . $object . '.attrRef(' . $prop . ')'; + } + + $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($expr->expr) . ';'; + return $left . ' = ' . $tmpVar . '.toReference()'; } protected function parseMethodCall(Node\Expr\MethodCall $expr): string