diff --git a/src/Php/AstNodeType.php b/src/Php/AstNodeType.php index 38d966e7..45b073d2 100644 --- a/src/Php/AstNodeType.php +++ b/src/Php/AstNodeType.php @@ -75,6 +75,11 @@ trait AstNodeType return $expr instanceof Expr\FuncCall; } + protected function isRefvalCall(NodeAbstract $expr): bool + { + return $this->isFuncCallExpr($expr) and $this->isNameExpr($expr->name) and $expr->name->toString() === 'refval'; + } + protected function isMethodCall(NodeAbstract $expr): bool { return $expr instanceof Expr\MethodCall; diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index e504c523..bb511ef3 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -2665,6 +2665,9 @@ class CompilerBase extends \PhpAot\Core\Translator return '{' . implode(', ', $list_args) . '}'; } + /** + * 仅用于动态调用的参数解析 + */ protected function parseArgRefVar(Node\Arg $arg, string $name): string { if (!$this->hasVar($name)) { @@ -2681,6 +2684,7 @@ class CompilerBase extends \PhpAot\Core\Translator $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();'; $name = $tmpVar; } + // 动态调用,参数列表是 Variant 类型而不是 Reference,必须使用 & 符号取地址,传递指针,以保持引用传递 return '&' . $name; } @@ -3334,6 +3338,14 @@ class CompilerBase extends \PhpAot\Core\Translator $type = $this->detectTypeOfExpr($arg->value); if ($argInfo->byRef) { + if ($this->isRefvalCall($arg->value)) { + if (count($arg->value->args) === 1 and $this->isVarExpr($arg->value->args[0]->value)) { + // 消除 refval() 函数调用,直接使用变量 + $arg->value = $arg->value->args[0]->value; + } else { + $this->fatalError($arg, 'The refval function only accepts one parameter of variable type'); + } + } if ($this->isVarExpr($arg->value)) { $var = $this->parseVariable($arg->value); // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 diff --git a/src/gen_stub.php b/src/gen_stub.php index b380dff1..84aac6a4 100755 --- a/src/gen_stub.php +++ b/src/gen_stub.php @@ -3673,7 +3673,7 @@ class ClassInfo { "class_{$escapedName}_$key", $allConstInfos, $this->phpVersionIdMinimumCompatibility, - $declaredStrings + refval($declaredStrings) ); } diff --git a/src/polyfills.php b/src/polyfills.php index 5fc69854..b6bc0556 100644 --- a/src/polyfills.php +++ b/src/polyfills.php @@ -38,3 +38,8 @@ function objval(mixed $obj, string $class): object } throw new Exception('Invalid object type'); } + +function &refval(&$var) +{ + return $var; +} diff --git a/tests/aot/ref/refval.phpt b/tests/aot/ref/refval1.phpt similarity index 100% rename from tests/aot/ref/refval.phpt rename to tests/aot/ref/refval1.phpt diff --git a/tests/aot/ref/refval2.phpt b/tests/aot/ref/refval2.phpt new file mode 100644 index 00000000..8e86c43c --- /dev/null +++ b/tests/aot/ref/refval2.phpt @@ -0,0 +1,16 @@ +--TEST-- +refval +--FILE-- + +--EXPECT-- +php refval test \ No newline at end of file