考虑这个示例性代码片段:
/**
* @throws \DomainException
*/
public function doFoo()
{
try {
// Do a unit of work with in a transaction.
// This code could throw a SomeOtherException.
// In this case the transaction should be rolled back
// and a \DomainException should be thrown.
} catch (SomeOtherException $e1) {
try {
$this->pdo->rollback();
throw new \DomainException("Failed", 0, $e1);
} catch (\PDOException $e2) {
// $e2 is lost!
throw new \DomainException("Failed even more", 0, $e1);
}
}
}
不可变合约只允许抛出DomainException
。
我对第二个catch块(内部catch (PDOException $e2)
)感兴趣。我可以使用$ e1或$ e2作为前一个例外,但不能同时使用两者。
我不喜欢吞下一个例外(在这种情况下是$ e2)。那么我怎么能抛出完整的错误信息,即包含$ e1和$ e2的\ DomainException呢?我在考虑将$ e1添加到$ e2的根目录并使用$ e2作为之前的版本,但PHP Exception
是不可变的。
编辑:PDO只是一个示例性用例。我也可以是任何其他API,我可能会对两种异常的堆栈跟踪感兴趣。
Edit2:将此视为一个无法更改的接口实现。
Edit3:Java Throwable.addSupressed()
完全适合这里。这可能有助于理解用例。
答案 0 :(得分:0)
您可能会这样做:
catch (\PDOException $e2) {
// Probably you do even need to pass more parameters
// to PDOException() to make it an exact "clone|brother".
// However, should get the concept out of it.
$e = new \PDOException($e2->getMessage(), 0, $e1);
throw $e;
}
不幸的是,在这种情况下你会松开$e2
(PDOException)的堆栈跟踪。要解决此问题,您可以使用$domainException
和$rollbackException
这两个附加属性创建自定义例外。您可以简单地覆盖该类中的getMessage()并组合嵌套异常的消息,以在日志文件中获取一致的错误消息。
答案 1 :(得分:0)
我发现确实finally
会自动完成所有操作:
try {
throw new Exception("A");
} finally {
throw new Exception("B");
}
这将打印:
PHP致命错误:未捕获的异常'异常'消息' A'在/home/malkusch/tmp/test.php:4 堆栈跟踪:
#0 {main}
下一个例外'异常'留言' B'在/home/malkusch> /tmp/test.php:7 堆栈跟踪:
#0 {main}
我没有想到,因为两个例外之间没有因果关系,但是Exception::getPrevious()
可接受的没有指定进一步的语义。
不幸的是,这是无证件行为,不能被视为稳定。 Bug #68270表明目前没有人知道预期的行为应该是什么。所以依靠它是不安全的。让我们看看discussion in internals会带来什么。