refactor(php): 重构PHP编译器中的赋值表达式处理逻辑

- 添加 inAssignExpr 属性来跟踪赋值表达式状态
- 修改 parseAssign 和 parseAssignRef 方法以设置赋值表达式标志
- 将 parseAssign 中的数组维度赋值逻辑提取到 parseAssignArrayDim 方法
- 将属性获取逻辑从 offsetGet 更改为 offsetGetIndirect
- 移除不正确的静态属性获取处理代码
- 添加 object link 和 property assign op 测试用例
pull/1/head
韩天峰 7 months ago
parent 1b78fc7fd9
commit f48b1f4781
  1. 75
      src/Php/CompilerBase.php
  2. 15
      tests/aot/object-link.phpt
  3. 11
      tests/aot/property-assign-op.phpt

@ -135,6 +135,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $beforeStmtLines = [];
protected array $afterStmtLines = [];
protected bool $inLoop = false;
protected bool $inAssignExpr = false;
protected bool $stubFile = false;
protected bool $stubFileIncluded = false;
protected Parser $parser;
@ -534,9 +535,15 @@ class CompilerBase extends \PhpAot\Core\Translator
case 'Expr_Empty':
return $this->parseEmpty($expr);
case 'Expr_Assign':
return $this->parseAssign($expr);
$this->inAssignExpr = true;
$result = $this->parseAssign($expr);
$this->inAssignExpr = false;
return $result;
case 'Expr_AssignRef':
return $this->parseAssignRef($expr);
$this->inAssignExpr = true;
$result = $this->parseAssignRef($expr);
$this->inAssignExpr = false;
return $result;
case 'Expr_Print':
return $this->parsePrint($expr);
case 'Expr_BinaryOp_Equal':
@ -712,35 +719,43 @@ class CompilerBase extends \PhpAot\Core\Translator
}
}
protected function parseAssign(Node $v): string
protected function parseAssignArrayDim(Node $left, Node $right): string
{
if ($this->isPropertyFetch($left)) {
return $this->parseAssignPropertyArrayDim($left, $right);
}
$array = $this->parseIdentifier($left->var);
$code = '';
// 这是 PHP 的初始化+赋值写法,需要先创建数组
if (!$this->hasVar($array) and $this->isVarExpr($left->var)) {
$this->addLocalVar($array, self::TYPE_ARRAY);
}
$value = $this->trimBrackets($this->parseExpr($right));
if ($left->dim === null) {
return $code . "$array.offsetSet(php::null, $value)";
} else {
$dim = $this->trimBrackets($this->parseIdentifier($left->dim));
return $code . "$array.offsetSet($dim, $value)";
}
}
protected function parseAssignPropertyFetch(Node $left, Node $right): string
{
$array = $this->parseIdentifier($left->var);
$propName = $this->identifierToStr($left->name);
return "$array.setProperty($propName, " . $this->trimBrackets($this->parseExpr($right)) . ")";
}
protected function parseAssign(Node\Expr\Assign $v): string
{
$left = $v->var;
$right = $v->expr;
if ($left->getType() === self::EXPR_ARRAY_DIM_FETCH) {
$array = $this->parseIdentifier($left->var);
$code = '';
// 这是 PHP 的初始化+赋值写法,需要先创建数组
if (!$this->hasVar($array) and $this->isVarExpr($left->var)) {
$this->addLocalVar($array, self::TYPE_ARRAY);
}
// 这是属性赋值操作
if ($this->isPropertyFetch($left->var)) {
return $this->parseAssignPropertyArrayDim($left, $right);
}
$value = $this->trimBrackets($this->parseExpr($right));
if ($left->dim === null) {
return $code . "$array.offsetSet(php::null, $value)";
} else {
$dim = $this->trimBrackets($this->parseIdentifier($left->dim));
return $code . "$array.offsetSet($dim, $value)";
}
return $this->parseAssignArrayDim($left, $right);
} elseif ($left->getType() === 'Expr_PropertyFetch') {
$array = $this->parseIdentifier($left->var);
$propName = $this->identifierToStr($left->name);
return "$array.setProperty($propName, " . $this->trimBrackets($this->parseExpr($right)) . ")";
return $this->parseAssignPropertyFetch($left, $right);
} elseif ($left->getType() === 'Expr_StaticPropertyFetch') {
$class = $this->identifierToStr($left->class);
$propName = $this->identifierToStr($left->name);
@ -789,7 +804,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$this->hasVar($var)) {
$this->addLocalVar($var, self::TYPE_VAR);
}
$code .= "$var = $tmpVar.offsetGet($k); ";
$code .= "$var = $tmpVar.offsetGetIndirect($k); ";
} else {
abort($item);
}
@ -1258,10 +1273,6 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->convertExprType($expr, $type, $rightType) . ';';
}
return $this->parseArrayDimStore($node->var->var, $dim, $tmpVar);
} elseif ($this->isPropertyFetch($node->var)) {
$obj = $this->parseIdentifier($node->var->var);
$prop = $this->identifierToStr($node->var->name);
return $obj . '.setProperty(' . $prop . ', ' . $obj . '.getProperty(' . $prop . ') ' . $this->removeAssignOp($op) . ' ' . $expr . ')';
} else {
return $var . ' ' . $op . ' (' . $expr . ')';
}
@ -1328,7 +1339,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->fatalError($node, 'Unsupported operand types: null + array');
}
$dim = $this->parseIdentifier($node->dim);
return $var . '.offsetGet(' . $this->trimBrackets($dim) . ')';
return $var . '.offsetGetIndirect(' . $this->trimBrackets($dim) . ')';
}
protected function parseArrayDimStore($array, $dim, $var): string
@ -2009,7 +2020,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parsePropertyFetch(Node\Expr\PropertyFetch $expr): string
{
return $this->convertToObject($expr->var) . '.getProperty("' . $this->parseIdentifier($expr->name) . '")';
return $this->convertToObject($expr->var) . '.getPropertyIndirect("' . $this->parseIdentifier($expr->name) . '")';
}
protected function parseAssignOpShiftRight(Node $node): string

@ -0,0 +1,15 @@
--TEST--
object link operator
--FILE--
<?php
function main()
{
$o = new stdClass();
$o->prop = ['dim2' => ['dim3' => 'value']];
$o->prop['dim2']['dim3'] = 'hello';
var_dump($o->prop['dim2']['dim3']);
}
?>
--EXPECT--
string(5) "hello"

@ -0,0 +1,11 @@
--TEST--
property assign op
--FILE--
<?php
$o = new stdClass;
$o->a = 1024;
$o->a *= 2;
var_dump($o->a);
?>
--EXPECT--
int(2048)
Loading…
Cancel
Save