例外情况:这是一种好的做法吗?

Exceptions: Is this a good practice?

提问人:Ross 提问时间:9/20/2008 最后编辑:John SlegersRoss 更新时间:1/12/2016 访问量:1504

问:

这是用PHP编写的,但它确实与语言无关。

try
{
    try
    {
        $issue = new DM_Issue($core->db->escape_string($_GET['issue']));
    }
    catch(DM_Exception $e)
    {
        throw new Error_Page($tpl, ERR_NOT_FOUND, $e->getMessage());
    }
}
catch(Error_Page $e)
{
    die($e);
}

嵌套的 try, catch 块是一个值得遵循的好做法吗?仅对于错误页面来说,这似乎有点笨重 - 但是,如果发生错误,我的问题数据管理器会抛出异常,我认为这是一种很好的错误检测方法。

Error_Page异常只是一个错误页编译器。

我可能只是迂腐,但你认为这是报告错误的好方法吗,如果是这样,你能建议一个更好的方法来写这个吗?

谢谢

PHP 语言无关 错误处理

评论

0赞 Aeon 9/20/2008
哦,并更改帖子的标题以更好地反映主题;“这是一个好的做法吗”并不是真正的描述性。“Exceptions: Nested try/catch blocks”怎么样?

答:

2赞 oglester 9/20/2008 #1

我想你最好不要筑巢。如果需要多种异常类型,请具有多个捕获。

try{
  Something();
}
catch( SpecificException se )
{blah();}
catch( AnotherException ae )
{blah();}

评论

0赞 Ross 9/20/2008
在这种情况下,多次捕获的问题是我可以捕获DM_Exception或Error_Page - 这不是我想做的。
0赞 oglester 10/2/2008
如果你发现一个你想被忽略的特定异常,只需使用 throw;(它只是重新抛出异常)或抛出新的 MyException(“这是我的错误”, innerException)(创建一个新异常并使用 innerException 构建堆栈跟踪)。
0赞 sgibbons 9/20/2008 #2

根据您的需要,这可能很好,但我通常非常犹豫是否要捕获异常,将消息包装在新的异常中,然后重新抛出它,因为您丢失了包装异常中原始异常的堆栈跟踪(以及可能的其他)信息。如果您确定在检查包装异常时不需要该信息,那么它可能没问题。

评论

0赞 Tim Frey 9/20/2008
我认为这取决于语言。我确信,在 Java 中,您可以“链接”异常,这样在重新抛出时就不会丢失原始堆栈跟踪。
8赞 Jeremy Privett 9/20/2008 #3

您正在将 Exceptions 用于页面逻辑,我个人认为这不是一件好事。异常应用于在发生不良或意外情况时发出信号,而不是控制错误页面的输出。如果要基于异常生成错误页面,请考虑使用 set_exception_handler。任何未捕获的异常都将通过您指定的任何回调方法运行。请记住,这并不能阻止异常的“致命性”。通过回调传递异常后,执行将像正常一样在任何未捕获的异常后停止。

0赞 Anheledir 9/20/2008 #4

我不确定 PHP,但在例如 C# 中,您可以有多个 catch-Block,因此不需要嵌套的 try/catch-combinations。

一般来说,我相信使用 try/catch/finally 进行错误处理始终是常识性的,也用于显示“仅”错误页面。这是一种处理错误和避免崩溃时出现奇怪行为的干净方法。

评论

0赞 Andrei Rînea 9/20/2008
C# 和 PHP 可以为一个 try 块提供多个 catch 块。
2赞 Steve Jessop 9/20/2008 #5

理想的情况是在可以处理异常的级别捕获异常。不是之前(浪费时间),也不是之后(你失去上下文)。

因此,如果 $tpl 和 ERR_NOT_FOUND 是仅在新DM_Issue调用附近“已知”的信息,例如,因为您在其他地方创建了DM_Issue并希望ERR_SOMETHING_ELSE,或者因为$tpl的值不同,那么您将在正确的位置捕获第一个异常。

如何从那个地方到死亡是另一个问题。另一种选择是死在那里。但是,如果你这样做,那么干预代码就没有机会在错误发生后但在退出之前做任何事情(例如以某种方式清除某些内容或修改错误页面)。拥有明确的控制流也很好。所以我觉得你很好。

我假设您的示例不是一个完整的应用程序 - 如果是,那么它可能是不必要的冗长,您可能会死在DM_Exception捕获子句中。但对于一个真正的应用程序,我赞成不只是在茫茫人海中死去的原则。

0赞 Aeon 9/20/2008 #6

我不会在未找到问题时抛出异常 - 这是应用程序的有效状态,您不需要堆栈跟踪来显示 404。

您需要捕获的是意外的失败,例如 sql 错误 - 这时异常处理就派上用场了。我会将您的代码更改为更像这样:

try {
    $issue = DM_Issue::fetch($core->db->escape_string($_GET['issue']));
}
catch (SQLException $e) {
    log_error('SQL Error: DM_Issue::fetch()', $e->get_message());
}
catch (Exception $e) {
    log_error('Exception: DM_Issue::fetch()', $e->get_message());
}

if(!$issue) {
    display_error_page($tpl, ERR_NOT_FOUND);
}
else
{
    // ... do stuff with $issue object.
}
0赞 user19302 9/20/2008 #7

仅当存在潜在的站点中断事件(例如数据库查询未正确执行或某些内容配置错误)时,才应使用异常。一个很好的例子是,Apache 进程无法写入缓存或日志目录。

这里的想法是,例外情况是针对开发人员的,用于停止可能破坏整个站点的代码,以便您可以在部署之前修复它们。它们也是健全性检查,以确保如果环境发生变化(即有人更改缓存文件夹的权限或更改数据库方案),则站点在损坏任何内容之前停止。

所以,不;嵌套捕获处理程序不是一个好主意。在我的页面中,我的 index.php 文件将其代码包装在尝试中...缓存块 - 如果发生不好的事情,它会检查它是否在生产中;然后给我发电子邮件并显示一般错误页面,或者直接在屏幕上显示错误。

请记住:PHP 不是 C#。C# 是(除了 ASP.net 的双关语(呵呵,没有双关语的:p))用于包含状态的应用程序 - 而 PHP 是一种无状态脚本语言。