首页 > 解决方案 > 如何最好地处理 catch 块中抛出的异常?

问题描述

假设我有一个 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;
}

但这并不完美,我仍然丢失了一些关于回滚异常的信息,比如它的堆栈跟踪。

我还尝试创建另一个包含两个异常的异常类:

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()。

有没有更好的方法或一些最佳实践来处理这样的案例?

标签: php

解决方案


推荐阅读