背景故事:我有一个处理数据库查询的类。问题是查询仅在需要时执行,因此有时可能会远离创建它的位置。现在,如果包装的SQL查询失败,则很难将其追溯到它的原点。
现在的想法是这样的:在创建包装器时,我将创建一个通用的异常对象(它给我回溯和一切)。当在实际执行期间发生某些事情时,预先生成的异常可用于在调试时找到问题的根源。
这不可避免地导致了一个问题:事先生成Exception
对象的成本有多高?它甚至是一件聪明的事情吗?你将如何调试延迟的SQL执行?
为了澄清这个过程,这里有一些伪代码:
$list = new QueryWrapper("SELECT ...");
$list->setPage(5);
// Later...
foreach ($list as $entry) { ... }
只有当foreach实际访问$list
时才执行查询。
更新:这是一个简约的实现:
public function __construct($query, ... $params = array()) {
...
$this->createTrace = new \Exception();
}
// called by the Iterator's rewind()
private function runQuery() {
try {
// execute query;
}
catch(\Exception $e) {
throw new \Exception(
sprintf(
'Exception thrown after SQL error (created as %s)',
$this->createTrace->getTraceAsString()
),
0, $e
);
}
}
答案 0 :(得分:2)
实例化可能在以后抛出的异常听起来像是一个非常不寻常的想法,可能不是我所期望的。我的意思是,正常情况是不抛出异常。所以,大多数情况下你会创建一个可能永远不会被抛出/使用的异常。
在程序流程中稍后抛出的异常会给你堆栈跟踪,所以在我看来:不要打扰也不要那样做。
答案 1 :(得分:0)
在生产环境中,我认为性能“损失”可以忽略不计,因为创建Exception
对象与创建任何类相同,这几乎不会受到任何影响。
我不确定这是解决问题的正确方法。这是你期望做的吗?
$list = new QueryWrapper("SELECT ...");
$list->exception = new Exception();
答案 2 :(得分:0)
简单的3v4l测试:
差异似乎很小(在3v4l.org硬件上,每个异常创建大约1-10 us) - 如果每个请求运行几十个查询,则不到一毫秒,即使对于高性能也不太相关网络应用程序)。