fix(compiler): 修复 finally 使用变量

pull/12/head
Yurun 2 months ago
parent bc799fda0a
commit d0cb1395e5
  1. 32
      src/Php/CompilerBase.php
  2. 29
      tests/aot/exception/finally-use-var.phpt

@ -6556,12 +6556,26 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
$finally = $v->finally;
$stmts = $finally ? $this->injectFinallyBeforeReturn($v->stmts, $finally->stmts) : $v->stmts;
$catches = $v->catches;
// Pre-register catch variables before parsing the try block so that
// injected finally code referencing catch variables (e.g. $e) does not
// trigger undefined-variable errors.
if ($finally) {
foreach ($catches as $catch) {
if ($catch->var) {
$varName = $this->parseIdentifier($catch->var);
if (!$this->hasVar($varName)) {
$this->addLocalVar($varName, self::TYPE_OBJECT);
}
}
}
}
$code .= PHP_EOL;
$code .= $this->parseBlockStmts($stmts);
$code .= $this->getIndent() . '}' . PHP_EOL;
$catches = $v->catches;
$exVar = $this->genTmpVarName();
$this->addLocalVar($exVar, self::TYPE_VAR);
@ -6695,7 +6709,19 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
$this->indentLevel++;
$code .= $this->getIndent() . "{$exVar} = php::null;" . PHP_EOL;
$stmts = $finallyStmts ? $this->injectFinallyBeforeReturn($catch->stmts, $finallyStmts) : $catch->stmts;
$code .= $this->parseStmts($stmts);
if ($finallyStmts) {
$code .= $this->getIndent() . 'try {' . PHP_EOL;
$this->indentLevel++;
$code .= $this->parseStmts($stmts);
$this->indentLevel--;
$code .= $this->getIndent() . '} catch(zend_object *_catch_throw_ex) {' . PHP_EOL;
$this->indentLevel++;
$code .= $this->getIndent() . "{$exVar} = php::catchException();" . PHP_EOL;
$this->indentLevel--;
$code .= $this->getIndent() . '}' . PHP_EOL;
} else {
$code .= $this->parseStmts($stmts);
}
$this->indentLevel--;
$code .= $this->getIndent() . '}';

@ -0,0 +1,29 @@
--TEST--
try-catch-finally: finally block must execute when exception is re-thrown inside catch block. Verifies that finally can access the caught exception variable ($e) even when the catch block re-throws it.
--FILE--
<?php
function main() {
try {
$a = 1;
throw new RuntimeException('test');
return 0; // trigger bug
} catch (\Throwable $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
throw $e;
} finally {
var_dump($a);
echo 'Finally exception: ', $e->getMessage(), "\n";
}
var_dump('This should not be reached');
}
?>
--EXPECT--
Caught exception: test
int(1)
Finally exception: test
Fatal error: Uncaught RuntimeException: test in Unknown(0) : eval():1
Stack trace:
#0 Unknown(0) : eval()(1): main()
#1 {main}
thrown in Unknown(0) : eval() on line 1
Loading…
Cancel
Save