From bffa660427a5f06b5b016c16f735de35a432b42d Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 7 Jul 2026 15:00:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BC=95=E5=85=A5=20parseWritableI?= =?UTF-8?q?dentifier=20=E6=9B=BF=E4=BB=A3=E6=89=8B=E5=8A=A8=20inAssignExpr?= =?UTF-8?q?=20=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Php/CompilerBase.php | 73 ++++++++++++++++++++++---------- src/Php/Parser/AssignOpTrait.php | 43 +++++-------------- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 93002716..20cef38a 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -107,6 +107,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont protected const string NATIVE_PROPERTY_VALUE_VAR = 'var'; protected const string NATIVE_PROPERTY_VALUE_DYNAMIC = 'dynamic'; + protected const string ATTR_ARRAY_DIM_FETCH_UPDATE = 'aotArrayDimFetchUpdate'; /** * Keyword methods (to* builtins) with mandated return types. @@ -625,7 +626,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont case 'Expr_Array': return $this->parseArray($expr); case 'Expr_ArrayDimFetch': - return $this->parseArrayDimFetch($expr, $this->context->inAssignExpr); + return $this->parseArrayDimFetch($expr); case 'Expr_PropertyFetch': return $this->parsePropertyFetch($expr, $this->context->inAssignExpr); case 'Expr_NullsafePropertyFetch': @@ -2933,12 +2934,8 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont protected function parsePreInc(Expr\PreInc $expr): string { $this->assertNotNullsafeWriteContext($expr->var); - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $result = $this->genDynamicPropIncDec($expr->var, '+', true); if ($result !== null) { - $this->context->inAssignExpr = $oriInAssignExpr; return $result; } @@ -2946,8 +2943,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { $this->fatalError($expr, 'Cannot use ++ on ' . $type . '. Use += 1 instead (Big* types are immutable).'); } - $result = '++' . $this->parseIdentifier($expr->var); - $this->context->inAssignExpr = $oriInAssignExpr; + $result = '++' . $this->parseWritableIdentifier($expr->var); return $result; } @@ -3016,8 +3012,48 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont return 'php::global(' . $this->parseIdentifier($node->dim) . ')'; } - protected function parseArrayDimFetch(Expr\ArrayDimFetch $node, bool $write): string + protected function parseWritableIdentifier(NodeAbstract $expr): string + { + if ($expr instanceof Expr\ArrayDimFetch) { + return $this->parseArrayDimFetchUpdate($expr); + } + + $oriInAssignExpr = $this->context->inAssignExpr; + $this->context->inAssignExpr = true; + $code = $this->parseIdentifier($expr); + $this->context->inAssignExpr = $oriInAssignExpr; + return $code; + } + + protected function parseArrayDimFetchRead(Expr\ArrayDimFetch $node): string { + return $this->parseArrayDimFetchWithUpdate($node, false); + } + + protected function parseArrayDimFetchUpdate(Expr\ArrayDimFetch $node): string + { + return $this->parseArrayDimFetchWithUpdate($node, true); + } + + protected function parseArrayDimFetchWithUpdate(Expr\ArrayDimFetch $node, bool $update): string + { + $attributes = $node->getAttributes(); + $node->setAttribute(self::ATTR_ARRAY_DIM_FETCH_UPDATE, $update); + try { + return $this->parseArrayDimFetch($node); + } finally { + $node->setAttributes($attributes); + } + } + + protected function isArrayDimFetchUpdate(Expr\ArrayDimFetch $node): bool + { + return $node->getAttribute(self::ATTR_ARRAY_DIM_FETCH_UPDATE, false) === true; + } + + protected function parseArrayDimFetch(Expr\ArrayDimFetch $node): string + { + $write = $this->isArrayDimFetchUpdate($node); if ($this->isStdContainerExpr($node)) { if ($write && $node->dim === null) { return $this->parseIdentifier($node->var); @@ -3025,7 +3061,9 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont return $this->parseStdContainerDimFetch($node); } - $var = $this->parseIdentifier($node->var); + $var = $write && $node->var instanceof Expr\ArrayDimFetch + ? $this->parseArrayDimFetchUpdate($node->var) + : $this->parseIdentifier($node->var); if ($this->isVarExpr($node->var)) { if ($var === 'GLOBALS') { return $this->parseGlobalsArrayDimFetch($node); @@ -4030,10 +4068,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont } if ($this->isVarExpr($expr->var) or $this->isPropertyFetch($expr->var) or $this->isArrayDimFetch($expr->var)) { - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($expr->var); - $this->context->inAssignExpr = $oriInAssignExpr; + $var = $this->parseWritableIdentifier($expr->var); if ($this->isVarExpr($expr->var) and !$this->hasVar($var)) { $this->errorUndefinedVariable($expr->var); } @@ -4213,12 +4248,8 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont protected function parsePreDec(Expr\PreDec $expr): string { $this->assertNotNullsafeWriteContext($expr->var); - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $result = $this->genDynamicPropIncDec($expr->var, '-', true); if ($result !== null) { - $this->context->inAssignExpr = $oriInAssignExpr; return $result; } @@ -4226,8 +4257,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { $this->fatalError($expr, 'Cannot use -- on ' . $type . '. Use -= 1 instead (Big* types are immutable).'); } - $result = '--' . $this->parseIdentifier($expr->var); - $this->context->inAssignExpr = $oriInAssignExpr; + $result = '--' . $this->parseWritableIdentifier($expr->var); return $result; } @@ -5206,10 +5236,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont $code .= $this->parseForeachItemAsList($nestedTmpVar, $item->value->items); continue; } - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($item->value); - $this->context->inAssignExpr = $oriInAssignExpr; + $var = $this->parseWritableIdentifier($item->value); if ($this->isVarExpr($item->value) and !$this->hasVar($var)) { $this->addLocalVar($var, self::TYPE_VAR); } diff --git a/src/Php/Parser/AssignOpTrait.php b/src/Php/Parser/AssignOpTrait.php index 23c8de34..39603a2d 100644 --- a/src/Php/Parser/AssignOpTrait.php +++ b/src/Php/Parser/AssignOpTrait.php @@ -29,10 +29,7 @@ trait AssignOpTrait $this->addLocalVar($tmp, self::TYPE_VAR); return '((' . $tmp . ' = ' . $value . ', ' . $target . ' = ' . $tmp . '), ' . $tmp . ')'; } - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $array = $this->parseIdentifier($left->var); - $this->context->inAssignExpr = $oriInAssignExpr; + $array = $this->parseWritableIdentifier($left->var); $code = ''; if (!$this->hasVar($array) and $this->isVarExpr($left->var)) { $this->addLocalVar($array, self::TYPE_ARRAY); @@ -125,10 +122,7 @@ trait AssignOpTrait $code .= "{$nestedTmp} = {$tmpVar}.item({$key}); "; $code .= $this->parseAssignToList($item->value, new Variable($nestedTmp)); } else { - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($item->value); - $this->context->inAssignExpr = $oriInAssignExpr; + $var = $this->parseWritableIdentifier($item->value); if ($this->isVarExpr($item->value) and !$this->hasVar($var)) { $this->addLocalVar($var, self::TYPE_VAR); } @@ -157,10 +151,7 @@ trait AssignOpTrait } if ($this->isVarExpr($left)) { - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($left); - $this->context->inAssignExpr = $oriInAssignExpr; + $var = $this->parseWritableIdentifier($left); if ($var === 'this_') { $this->fatalError($left, 'Cannot re-assign $this'); } @@ -282,10 +273,7 @@ trait AssignOpTrait $this->assertCanAssignPropertyWrite($propertyWriteTarget, $right); } - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($left); - $this->context->inAssignExpr = $oriInAssignExpr; + $var = $this->parseWritableIdentifier($left); $rightExpr = $this->parseAssignRightExpr($right); if ($propertyWriteTarget !== null) { $rightExpr = $this->wrapPropertyWriteTypeCheck($propertyWriteTarget, $right, $rightExpr); @@ -334,10 +322,7 @@ trait AssignOpTrait protected function parseAssignOp(Expr\AssignOp $node, string $op): string { $this->assertNotNullsafeWriteContext($node->var); - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($node->var); - $this->context->inAssignExpr = $oriInAssignExpr; + $var = $this->parseWritableIdentifier($node->var); $expr = $this->parseIdentifier($node->expr); $propertyWriteTarget = $this->preparePropertyWriteTarget($node->var); $this->guardLiteralDivisionByZero($node->expr, $op); @@ -386,7 +371,7 @@ trait AssignOpTrait $tmpVar = $this->genTmpVarName(); $this->addLocalVar($tmpVar, $rightType); $dim = $this->parseIdentifier($node->var->dim); - $readVar = $this->parseArrayDimFetch($node->var, false); + $readVar = $this->parseArrayDimFetchRead($node->var); $binaryOp = $this->removeAssignOp($op); if ($binaryOp === '.') { @@ -512,10 +497,7 @@ trait AssignOpTrait protected function parseArrayDimStore($array, $dim, $var): string { - $oriInAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $id = $this->parseIdentifier($array); - $this->context->inAssignExpr = $oriInAssignExpr; + $id = $this->parseWritableIdentifier($array); return $id . '.offsetSet(' . $dim . ', ' . $var . ')'; } @@ -542,9 +524,7 @@ trait AssignOpTrait $this->fatalError($expr->expr, 'Cannot take reference of a nullsafe chain'); } - $this->context->inAssignExpr = true; - $left = $this->parseIdentifier($expr->var); - $this->context->inAssignExpr = false; + $left = $this->parseWritableIdentifier($expr->var); if ($this->isVarExpr($expr->var)) { if (!$this->hasVar($left)) { @@ -567,7 +547,7 @@ trait AssignOpTrait $rightExpr = $tmpVar . ' = ' . $this->emitDynamicPropertyFetchRef($expr->expr, $expr); } elseif ($this->isArrayDimFetch($expr->expr)) { $left = $this->parseIdentifier($expr->var); - $array = $this->parseIdentifier($expr->expr->var); + $array = $this->parseWritableIdentifier($expr->expr->var); if ($expr->expr->dim == null) { $this->fatalError($expr, 'Cannot assign reference to array dim fetch without dim'); } @@ -602,10 +582,7 @@ trait AssignOpTrait $this->checkLeftValue($expr->var); $isset = $this->parseChainedExpr($expr->var, self::OP_ISSET); - $inAssignExpr = $this->context->inAssignExpr; - $this->context->inAssignExpr = true; - $var = $this->parseIdentifier($expr->var); - $this->context->inAssignExpr = $inAssignExpr; + $var = $this->parseWritableIdentifier($expr->var); $propertyWriteTarget = $this->preparePropertyWriteTarget($expr->var); if ($propertyWriteTarget !== null) {