From a5f397efa56a250ea81ee666fe41cd7f6ac38fc2 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 27 Mar 2026 20:02:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E5=AE=8C=E5=96=84=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E8=BF=94=E5=9B=9E=E5=80=BC=E7=B1=BB=E5=9E=8B=E6=8E=A8?= =?UTF-8?q?=E6=96=AD=E5=92=8C=E8=A7=A3=E6=9E=90=E5=AE=8C=E6=88=90=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E8=B7=9F=E8=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加函数解析完成状态标识符 completed 属性 - 在函数解析完成后设置 completed 标识为 true - 改进返回值类型变更时的日志输出,显示原类型到新类型的转换 - 优化方法调用返回值检测逻辑,仅在函数已完成解析时使用其返回值类型 - 修复内部函数返回值类型检测,排除 void 类型的干扰 - 更新对象表达式转换逻辑,确保表达式预处理正确执行 - 改进变量赋值错误提示信息,明确显示变量名称 - 添加返回值类型测试用例,验证 void 函数的赋值行为 - 修复命名空间类名获取逻辑,确保类名格式正确 --- src/Php/CompilerBase.php | 30 ++++++++++++++++++++---------- src/Php/Entity/FunctionDef.php | 1 + src/Php/Translator.php | 2 +- tests/aot/return-value.phpt | 13 +++++++++++++ 4 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 tests/aot/return-value.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 4aeb0691..4592cdd1 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -849,6 +849,7 @@ class CompilerBase extends \PhpAot\Core\Translator if (!$this->isReturnStmtInLastLine($v->stmts)) { $stmts .= $this->genReturnCode(); } + $this->functionDef->completed = true; } catch (Skip) { $this->climate->cyan('Skip function ' . $name); } @@ -1719,9 +1720,10 @@ class CompilerBase extends \PhpAot\Core\Translator protected function resetReturnType(Node\Stmt\Return_ $node, string $type): void { + $oriType = $this->functionDef->returnType; $this->functionDef->returnType = $type; // 返回值变更,需要重新解析 - $this->climate->cyan('Return type changed at line ' . $node->getLine() . ', retrying...'); + $this->climate->cyan("Return type changed ($oriType -> $type) at line {$node->getLine()} retrying..."); throw new Redo(); } @@ -1792,9 +1794,12 @@ class CompilerBase extends \PhpAot\Core\Translator $method = $this->parseIdentifier($expr->name); $nativeFunc = $this->findNativeMethod($expr, $object, $method); if ($nativeFunc) { - return $this->nativeFunctions[$nativeFunc]->returnType; - } - if ($this->isTypedObject($object)) { + $funcDef = $this->nativeFunctions[$nativeFunc]; + // 此函数尚未完成解析,仅经过初步的预处理,无法获得准确的返回值类型 + if ($funcDef->completed) { + return $funcDef->returnType; + } + } elseif ($this->isTypedObject($object)) { return $this->detectMethodCallReturnType($this->getObjectType($object), $method); } } @@ -3579,9 +3584,13 @@ class CompilerBase extends \PhpAot\Core\Translator protected function detectFuncCallReturnType(string $name): string { - $returnType = Reflection::getFunctionReturnType($name); - if ($returnType) { - return $this->getTypeFromZendType($returnType); + if ($this->isInternalFunction($name)) { + $returnType = Reflection::getFunctionReturnType($name); + // void 类型将被忽略,类型推测仅用于赋值操作的右值,即使返回值为 void , 赋值操作也应该继续运行,右值会被当做 null + // 例如 $a = var_dump('hello'); 虽然 var_dump 返回值为 void ,但是 $a 的类型是 mixed,值为 null + if ($returnType and $returnType !== 'void') { + return $this->getTypeFromZendType($returnType); + } } return self::TYPE_VAR; } @@ -3589,7 +3598,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected function detectMethodCallReturnType(string $class, string $method): string { $returnType = Reflection::getMethodReturnType($class, $method); - if ($returnType) { + if ($returnType and $returnType !== 'void') { return $this->getTypeFromZendType($returnType); } return self::TYPE_VAR; @@ -3978,8 +3987,9 @@ class CompilerBase extends \PhpAot\Core\Translator goto _to_object; } } else { + $ex = $this->parseIdentifier($expr->expr); _to_object: - $ex = $this->convertObjectExpr($expr->expr); + $ex = $this->convertObjectExpr($ex); } return 'php::throwException(' . $ex . ')'; } @@ -4208,7 +4218,7 @@ class CompilerBase extends \PhpAot\Core\Translator $this->addLocalVar($name, self::TYPE_VAR); } else { if ($this->getVarType($name) !== self::TYPE_VAR) { - $this->fatalError($node, 'Cannot assign value to variable of type ' . $this->getVarType($name)); + $this->fatalError($node, 'Cannot assign value to variable $' . $name . ' of type ' . $this->getVarType($name)); } } } diff --git a/src/Php/Entity/FunctionDef.php b/src/Php/Entity/FunctionDef.php index a0d7edb2..b596b61c 100644 --- a/src/Php/Entity/FunctionDef.php +++ b/src/Php/Entity/FunctionDef.php @@ -23,6 +23,7 @@ class FunctionDef public string $params = ''; public string $namespace = ''; public bool $method = false; + public bool $completed = false; public function __construct(string $name, string $returnType, string $namespace = '') { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 248df334..cdbb7ffb 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -865,7 +865,7 @@ class Translator extends Preprocessor $extends = $class->extends; } - $fullName = $this->getNamespacedClassName($this->class); + $fullName = ltrim($this->namespace . '\\' . $this->class, '\\'); if ($this->hasNativeClass($fullName)) { $this->classDef = $this->getClassDef($fullName); } else { diff --git a/tests/aot/return-value.phpt b/tests/aot/return-value.phpt new file mode 100644 index 00000000..651046de --- /dev/null +++ b/tests/aot/return-value.phpt @@ -0,0 +1,13 @@ +--TEST-- +object link operator +--FILE-- + +--EXPECT-- +string(3) "foo" +NULL \ No newline at end of file