test(compiler): add foreach array snapshot stability test case

- Add test case for foreach by value behavior when current element is removed
- Verify that foreach maintains stable array snapshot during iteration
- Confirm expected output matches array traversal before modifications
- Document behavior where unset operations don't affect ongoing loop

refactor(parser): simplify foreach array handling logic

- Remove dedicated parseForeachArray method from ForeachTrait
- Consolidate array iteration to use existing parseForeachIterable method
- Maintain same functional behavior while reducing code duplication
- Update type checking logic to route arrays
pull/18/head
韩天峰 1 month ago
parent aae4f2a07d
commit 324bf532bc
  1. 21
      src/Parser/ForeachTrait.php
  2. 29
      tests/compiler/loop/foreach-unset-current.phpt

@ -107,25 +107,6 @@ trait ForeachTrait
return $this->getIndent() . ' ' . $valueVar . ' = ' . $valueExpr . ';' . PHP_EOL;
}
protected function parseForeachArray(Foreach_ $node, string $iteratorVar): string
{
$tmpVar = $this->genTmpVarName();
$code = "for (auto $tmpVar = $iteratorVar.begin(); $tmpVar != $iteratorVar.end(); ++$tmpVar) {" . PHP_EOL;
$this->indentLevel++;
$code .= $this->parseForeachKeyAssignment($node, $tmpVar . '.key()');
$code .= $this->parseForeachValueAssignment($node, $tmpVar . '.value()', $tmpVar . '.valueRef()');
$body = $this->parseForeachBody($node);
$this->indentLevel--;
$code .= $this->parseBeforeStmtLines() . PHP_EOL;
$code .= $body . PHP_EOL;
$code .= $this->getIndent() . '}';
return $code;
}
protected function parseForeachIterable(Foreach_ $node, string $iterableVar): string
{
$iterator = $this->genTmpVarName();
@ -158,7 +139,7 @@ trait ForeachTrait
if ($this->hasVar($name)) {
$type = $this->getVarType($name);
if ($type === Type::ARRAY) {
return $this->parseForeachArray($node, $name);
return $this->parseForeachIterable($node, $name);
} elseif ($type === Type::OBJECT) {
if ($node->byRef) {
$this->fatalError($node, 'Cannot use & with foreach');

@ -0,0 +1,29 @@
--TEST--
foreach by value keeps a stable array snapshot when the current element is removed
--FILE--
<?php
function main(): void
{
$values = ['a' => 1, 'b' => 2, 'c' => 3];
$seen = [];
foreach ($values as $key => $value) {
$seen[] = $key . ':' . $value;
unset($values[$key]);
}
var_dump($seen);
var_dump($values);
}
?>
--EXPECT--
array(3) {
[0]=>
string(3) "a:1"
[1]=>
string(3) "b:2"
[2]=>
string(3) "c:3"
}
array(0) {
}
Loading…
Cancel
Save