Note some undocumented details about exceptions thrown from 'finally' blocks.
When exception is thrown from 'finally' block, it overrides the original not-caught (or re-thrown) exception. So the behavior is similar to 'return': value returned from 'finally' overrides the one returned earlier. And the original exception is automatically appended to the exceptions chain, i.e. becomes 'previous' for the new one. Example:
<?php
try {
try {
throw new Exception('thrown from try');
} finally {
throw new Exception('thrown from finally');
}
} catch(Exception $e) {
echo $e->getMessage();
echo PHP_EOL;
echo $e->getPrevious()->getMessage();
}
?>
Example with re-throwing:
<?php
try {
try {
throw new Exception('thrown from try');
} catch (Exception $e) {
throw new Exception('thrown from catch');
} finally {
throw new Exception('thrown from finally');
}
} catch(Exception $e) {
echo $e->getMessage();
echo PHP_EOL;
echo $e->getPrevious()->getMessage();
}
?>
The same happens even if explicitly pass null as previous exception:
<?php
try {
try {
throw new Exception('thrown from try');
} finally {
throw new Exception('thrown from finally', null, null);
}
} catch(Exception $e) {
echo $e->getMessage();
echo PHP_EOL;
echo $e->getPrevious()->getMessage();
}
?>
Also it is possible to pass previous exception explicitly, the 'original' one will be still appended to the chain, e.g.:
<?php
try {
try {
throw new Exception('thrown from try');
} finally {
throw new Exception(
'thrown from finally',
null,
new Exception('Explicitly set previous!')
);
}
} catch(Exception $e) {
echo $e->getMessage();
echo PHP_EOL;
echo $e->getPrevious()->getMessage();
echo PHP_EOL;
echo $e->getPrevious()->getPrevious()->getMessage();
}
?>
This seems to be true for versions 5.6-8.2.