例外:这是一个好习惯吗?

时间:2020-03-06 14:26:54  来源:igfitidea点击:

这是用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);
}

嵌套尝试,捕获块是遵循的好习惯吗?似乎仅对于错误页面来说有点笨重,但是如果发生错误,我的Issue Datamanager会引发异常,我认为这是检测错误的一种好方法。

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

我可能只是个书呆子,但是我们认为这是报告错误的好方法吗?

谢谢

解决方案

我认为最好不要嵌套。如果我们期望多个异常类型,则有多个捕获。

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

根据需求,这可能很好,但是我通常会很犹豫地捕获异常,将消息包装在新的异常中,然后重新抛出它,因为我们从包装中的原始异常中释放了堆栈跟踪(以及其他可能的信息)例外。如果确定在检查包装异常时不需要该信息,那么可能就可以了。

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

我不确定PHP,但例如C我们可以拥有一个以上的catch-Block,因此不需要嵌套的try / catch-combinations。

通常,我认为使用try / catch / finally进行错误处理始终是常识,也用于"仅"显示错误页面。这是处理错误并避免崩溃时的奇怪行为的一种干净方法。

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

因此,如果$ tpl和ERR_NOT_FOUND是仅在新DM_Issue调用附近"已知"的信息,例如,因为在其他地方创建DM_Issue并需要ERR_SOMETHING_ELSE,或者因为$ tpl的值不同,那么我们在正确的位置捕捉​​到第一个例外。

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

我假设示例如果不是一个完整的应用程序,则可能是不必要的冗长,并且我们可能会死于DM_Exception catch子句。但是对于一个真正的应用程序,我赞成不只是虚无而死的原则。

我不会在未发现它是应用程序的有效状态的问题上抛出异常,并且我们不需要堆栈跟踪就可以显示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.
}

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

这里的想法是,异常是针对我们(开发人员)的,它可以终止可能破坏整个网站的代码,因此我们可以在部署之前对其进行修复。它们也是健全性检查,以确保如果环境发生变化(即有人更改了缓存文件夹的权限或者更改了数据库方案),则在该站点可能会损坏任何内容之前将其暂停。

所以不行;嵌套的捕获处理程序不是一个好主意。在我的页面中,我的index.php文件将其代码包装在try ... cache块中,如果发生不良情况,它将检查其是否在生产中。并通过电子邮件发送给我并显示一般错误页面,或者在屏幕上直接显示错误。

切记:PHP不是C#。对于包含状态的应用程序,Cis(ASP.net的例外情况(嘿,没有双关语:p)),而PHP是无状态脚本语言。