refactor(php): 重构PHP编译器中的引用参数处理逻辑

- 将引用参数处理逻辑提取到独立的parseArgRefVar方法中
- 简化了Scalar_String类型处理时的genCharPtr调用
- 添加了对refval函数的支持,允许通过函数调用传递引用参数
- 移除了重复的引用参数处理代码,提高代码复用性
- 修复了eval函数中使用的identifierToStr方法调用
- 添加了refval函数的测试用例
pull/1/head
韩天峰 4 months ago
parent c94d7afdba
commit 05854e55be
  1. 51
      src/Php/CompilerBase.php
  2. 15
      tests/aot/ref/refval.phpt

@ -917,7 +917,7 @@ class CompilerBase extends \PhpAot\Core\Translator
case 'Scalar_Float':
return $this->parseScalarFloat($expr);
case 'Scalar_String':
return $expr->hasAttribute('noLiteralString') ? $this->genCharPtr($expr->value) : $this->getLiteralString($expr->value);
return $expr->hasAttribute('noLiteralString') ? $this->genCharPtr($expr->value, true) : $this->getLiteralString($expr->value);
default:
abort($expr);
break;
@ -2586,21 +2586,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isVarExpr($arg->value)) {
$name = $this->parseIdentifier($arg->value);
if ($byRef) {
if (!$this->hasVar($name)) {
// 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用
$this->addLocalVar($name, self::TYPE_REF);
} else {
// 本地变量,且是原生类型,则转为普通变量
if ($this->hasLocalVar($name) and $this->isNativeType($this->getVarType($name))) {
$this->context->localVars[$name] = self::TYPE_VAR;
}
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_REF);
$this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();';
$name = $tmpVar;
}
$list_args[] = '&' . $name;
$list_args[] = $this->parseArgRefVar($arg, $name);
continue;
}
if (!$this->hasVar($name)) {
@ -2639,6 +2625,18 @@ class CompilerBase extends \PhpAot\Core\Translator
$list_args[] = $array . '.itemRef(' . $this->identifierToStr($arg->value->dim) . ')';
continue;
}
} elseif ($this->isFuncCallExpr($arg->value)) {
if ($this->isNameExpr($arg->value->name) and $arg->value->name->toString() === 'refval') {
if (count($arg->value->args) === 1 and $this->isVarExpr($arg->value->args[0]->value)) {
$name = $this->parseVariable($arg->value->args[0]->value);
// 消除 refval() 函数调用,直接使用变量
$arg->value = $arg->value->args[0]->value;
$list_args[] = $this->parseArgRefVar($arg, $name);
continue;
} else {
$this->fatalError($arg, 'The refval function only accepts one parameter of variable type');
}
}
} else {
if ($byRef) {
$list_args[] = $this->parseChainedExpr($arg->value, self::OP_REFVAL);
@ -2667,6 +2665,25 @@ class CompilerBase extends \PhpAot\Core\Translator
return '{' . implode(', ', $list_args) . '}';
}
protected function parseArgRefVar(Node\Arg $arg, string $name): string
{
if (!$this->hasVar($name)) {
// 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用
$this->addLocalVar($name, self::TYPE_REF);
} else {
// 本地变量,且是原生类型,则转为普通变量
if ($this->hasLocalVar($name) and $this->isNativeType($this->getVarType($name))) {
$this->context->localVars[$name] = self::TYPE_VAR;
}
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_REF);
$this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();';
$name = $tmpVar;
}
return '&' . $name;
}
protected function parseArg(Node\Arg $arg): string
{
return $this->parseIdentifier($arg->value);
@ -3702,7 +3719,7 @@ class CompilerBase extends \PhpAot\Core\Translator
{
// 对 eval() 指令的 PHP 代码段禁止字面量优化
$expr->expr->setAttribute('noLiteralString', true);
return 'php::eval(' . $this->parseIdentifier($expr->expr) . ')';
return 'php::eval(' . $this->identifierToStr($expr->expr) . ')';
}
protected function parseInclude(Expr\Include_ $expr): string

@ -0,0 +1,15 @@
--TEST--
refval
--FILE--
<?php
function main()
{
eval('function retval_test(&$name) { $name .= "refval test"; }');
$name = 'php ';
retval_test(refval($name));
echo $name;
}
?>
--EXPECT--
php refval test
Loading…
Cancel
Save