fix(parser): parse do-while body before condition

master
韩天峰 4 hours ago
parent 98321138ce
commit d321666721
  1. 8
      phpunit/code/control-flow/while-body-defined-condition.php
  2. 8
      phpunit/src/LoopControlTest.php
  3. 6
      src/Parser/LoopControlTrait.php
  4. 21
      tests/compiler/control_flow/do-while-body-defined-condition.phpt

@ -0,0 +1,8 @@
<?php
function while_body_defined_condition(): void
{
while (count($results) > 0) {
$results = [1, 2, 3];
}
}

@ -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',
);
}
}

@ -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;

@ -0,0 +1,21 @@
--TEST--
do-while condition can use a variable first defined in the loop body
--FILE--
<?php
function main(): void
{
$page = 1;
do {
$results = [1, 2, 3];
echo "page=$page count=", count($results), "\n";
$page++;
} while (count($results) === 3 && $page <= 2);
echo "Done\n";
}
?>
--EXPECT--
page=1 count=3
page=2 count=3
Done
Loading…
Cancel
Save