假设我有一个try / catch块,如果发生不好的情况,我需要在catch块中进行一些清理。 然后,我想抛出原始异常,让应用程序代码处理它。
例如,可以回滚这样的数据库事务:
try {
startTransaction();
doSomethingThatThrowsAnException();
} catch (Exception $e) {
rollbackTransaction();
throw $e;
}
很好,但是回滚可能会失败并且也会引发异常。然后,我的应用程序将仅看到回滚异常,而不是原始异常。然后,我将错过最有用的信息,这是不好的。
所以我可以将代码更改为此:
try {
startTransaction();
doSomethingThatThrowsAnException();
} catch (Exception $e) {
try {
rollbackTransaction();
} catch (Exception $ex) {
// Do nothing
}
throw $e;
}
那更好,但是现在我不知道清理/回滚也失败了。回滚功能中可能存在一个我永远不会发现的错误。 我想获得有关这两种例外情况的完整信息。
到目前为止,我能想到的最好的办法是创建一个新异常,保留有关回滚异常的消息,并像以前一样发送原始异常:
try {
startTransaction();
doSomethingThatThrowsAnException();
} catch (Exception $e) {
try {
rollbackTransaction();
} catch (Exception $ex) {
throw new Exception($ex->getMessage(), $ex->getCode(), $e);
}
throw $e;
}
但这并不完美,我仍然会丢失一些有关回滚异常的信息,例如其堆栈跟踪。
我还尝试创建另一个包含这两个异常的Exception-class:
try {
startTransaction();
doSomethingThatThrowsAnException();
} catch (Exception $e) {
try {
rollbackTransaction();
} catch (Exception $ex) {
throw new MultiException($e, $ex);
}
throw $e;
}
class MultiException extends Exception
{
private $exceptions = [];
public function __construct(...$exceptions)
{
$this->exceptions = $exceptions;
}
public function __toString()
{
return implode("\n", $this->exceptions);
}
}
但是我不确定这在各种日志记录框架中如何发挥作用。例如,只能覆盖__toString()方法,而不能覆盖getTrace()。
是否有更好的方法或最佳实践来处理此类案件?