diff --git a/phpunit/code/control-flow/while-body-defined-condition.php b/phpunit/code/control-flow/while-body-defined-condition.php new file mode 100644 index 00000000..75c6eeed --- /dev/null +++ b/phpunit/code/control-flow/while-body-defined-condition.php @@ -0,0 +1,8 @@ + 0) { + $results = [1, 2, 3]; + } +} diff --git a/phpunit/src/LoopControlTest.php b/phpunit/src/LoopControlTest.php index 3a7c47d1..d21a5b76 100644 --- a/phpunit/src/LoopControlTest.php +++ b/phpunit/src/LoopControlTest.php @@ -22,4 +22,12 @@ class LoopControlTest extends \BaseTest { $this->compile('control-flow/loop-switch-continue.php'); } + + public function testWhileConditionIsStillParsedBeforeItsBody(): void + { + $this->exec( + 'Undefined variable `$results`', + 'control-flow/while-body-defined-condition.php', + ); + } } diff --git a/src/Parser/LoopControlTrait.php b/src/Parser/LoopControlTrait.php index bc42888d..8cd9f48c 100644 --- a/src/Parser/LoopControlTrait.php +++ b/src/Parser/LoopControlTrait.php @@ -148,6 +148,10 @@ trait LoopControlTrait protected function parseDo(Node\Stmt\Do_ $v): string { $stmts = $v->stmts; + // A do-while body always runs before its condition. Parse it first so + // variables introduced by the body are available while lowering the + // condition, matching PHP's execution order. + $bodyCode = $this->parseBlockStmts($stmts); $this->assertExprCanBeUsedAsCondition($v->cond, 'do-while condition'); [$cond, $beforeStmts, $afterStmts] = $this->parseExprWithCapturedStmts($v->cond); if ($beforeStmts || $afterStmts) { @@ -167,7 +171,7 @@ trait LoopControlTrait } $code = $this->parseBeforeStmtLines() . PHP_EOL; $code .= 'do {' . PHP_EOL; - $code .= $this->parseBlockStmts($stmts); + $code .= $bodyCode; $code .= $this->genLoopEndFlagCheck(); $code .= $this->getIndent() . '} while (' . $cond . ');' . PHP_EOL; diff --git a/tests/compiler/control_flow/do-while-body-defined-condition.phpt b/tests/compiler/control_flow/do-while-body-defined-condition.phpt new file mode 100644 index 00000000..07820c8b --- /dev/null +++ b/tests/compiler/control_flow/do-while-body-defined-condition.phpt @@ -0,0 +1,21 @@ +--TEST-- +do-while condition can use a variable first defined in the loop body +--FILE-- + +--EXPECT-- +page=1 count=3 +page=2 count=3 +Done