From 67fc93c620b5789dc3d0474ab60e0675713a6e1f Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Wed, 18 Mar 2026 15:39:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(compiler):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E5=8F=98=E9=87=8F=E5=92=8C=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 getNativeFunction 方法用于获取原生函数定义 - 修改函数调用返回类型检测逻辑使用 getNativeFunction - 添加对引用参数的处理支持,包括变量引用和全局变量引用 - 实现 GLOBALS 数组访问的特殊处理逻辑 - 支持将字符串常量转换为全局变量名 - 添加临时变量创建用于引用传递场景 --- src/Php/CompilerBase.php | 41 ++++++++++++++++++++++++++++++++------ tests/aot/global-vars.phpt | 13 ++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index ed391124..43ab641c 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1549,6 +1549,11 @@ class CompilerBase extends \PhpAot\Core\Translator return array_key_exists($this->escapeFunction($name), $this->nativeFunctions); } + protected function getNativeFunction(string $name): FunctionDef + { + return $this->nativeFunctions[$this->escapeFunction($name)]; + } + protected function checkNativeFunction(string $name): void { // 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误 @@ -1661,7 +1666,7 @@ class CompilerBase extends \PhpAot\Core\Translator case 'Expr_FuncCall': $name = $this->parseIdentifier($expr->name); if ($this->hasNativeFunction($name)) { - return $this->functions[$name]->returnType; + return $this->getNativeFunction($name)->returnType; } return $this->detectFuncCallReturnType($name); case 'Expr_New': @@ -2289,9 +2294,10 @@ class CompilerBase extends \PhpAot\Core\Translator if ($arg->name !== null) { $this->fatalError($arg, 'Named arguments are not supported'); } + $byRef = $funcName && Reflection::isReferenceArg($funcName, $className, $i); if ($this->isVarExpr($arg->value)) { $name = $this->parseIdentifier($arg->value); - if ($funcName and Reflection::isReferenceArg($funcName, $className, $i)) { + if ($byRef) { if (!$this->hasVar($name)) { // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 $this->addLocalVar($name, self::TYPE_REF); @@ -2317,16 +2323,39 @@ class CompilerBase extends \PhpAot\Core\Translator if (!$this->hasVar($obj)) { $this->fatalError($arg, 'Undefined variable `$' . $obj . '`'); } - if ($funcName and Reflection::isReferenceArg($funcName, $className, $i)) { + if ($byRef) { $list_args[] = $obj . '.attrRef(' . $this->identifierToStr($arg->value->name) . ')'; continue; } } elseif ($this->isArrayDimFetch($arg->value) and $this->isVarExpr($arg->value->var)) { $array = $this->parseIdentifier($arg->value->var); - if ($this->isVarExpr($arg->value->var) and !$this->hasVar($array)) { + if ($array === 'GLOBALS') { + if ($arg->value->dim === null) { + $this->fatalError($arg, 'GLOBALS array dimension must be a constant expression'); + } + // $GLOBALS['var'] 等价于 global $var; $var ,将字符串常量转为变量名称即可 + // 仅限于字面量字符串可以转为变量名称,其他则使用 php::global 函数获取 + if ($arg->value->dim instanceof Node\Scalar\String_) { + $globalVar = $arg->value->dim->value; + if (!$this->hasGlobalVar($globalVar)) { + $this->addGlobalVar($globalVar, self::TYPE_VAR); + } + } else { + $globalVar = 'php::global(' . $this->parseExpr($arg->value->dim) . ')'; + } + // 全局变量作为引用参数 + if ($byRef) { + $ref = $this->addTmpVar(self::TYPE_REF); + $this->context->beforeStmtLines[] = $ref . ' = ' . $globalVar . '.toReference();'; + $list_args[] = '&' . $ref; + } else { + $list_args[] = $globalVar; + } + continue; + } elseif ($this->isVarExpr($arg->value->var) and !$this->hasVar($array)) { $this->fatalError($arg, 'Undefined variable `$' . $array . '`'); } - if ($funcName and Reflection::isReferenceArg($funcName, $className, $i)) { + if ($byRef) { if ($arg->value->dim === null) { $this->fatalError($arg, 'Array dimension must be a constant expression'); } @@ -2334,7 +2363,7 @@ class CompilerBase extends \PhpAot\Core\Translator continue; } } else { - if ($funcName and Reflection::isReferenceArg($funcName, $className, $i)) { + if ($byRef) { $list_args[] = $this->parseChainedExpr($arg->value, self::OP_REFVAL); continue; } diff --git a/tests/aot/global-vars.phpt b/tests/aot/global-vars.phpt index 75c3a922..c0bca06a 100644 --- a/tests/aot/global-vars.phpt +++ b/tests/aot/global-vars.phpt @@ -9,9 +9,22 @@ var_dump($GLOBALS['a']); var_dump($a); var_dump(gettype($_SERVER)); var_dump($_SERVER['argc']); + +parse_str('hello=world&lang=php', $GLOBALS['query']); +var_dump($GLOBALS['query']); + +$key = 'argc'; +var_dump($GLOBALS[$key]); ?> --EXPECTF-- int(100) int(100) string(5) "array" int(%d) +array(2) { + ["hello"]=> + string(5) "world" + ["lang"]=> + string(3) "php" +} +int(%d) \ No newline at end of file