【问题标题】:Exceptions: Is this a good practice?例外:这是一个好习惯吗?
【发布时间】:2010-09-11 08:11:21
【问题描述】:

这是用 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 异常只是一个错误页面编译器。

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

谢谢

【问题讨论】:

  • 哦,更改帖子标题以更好地反映主题; “这是一个好的做法”并不是真正的描述性。 “例外:嵌套的 try/catch 块”怎么样?

标签: php language-agnostic exception exception-handling error-handling


【解决方案1】:

我认为你最好不要嵌套。如果您期望有多种异常类型,请使用多个捕获。

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

【讨论】:

  • 在这种情况下,多个捕获的问题是我可以捕获 DM_Exception 或 Error_Page - 这不是我想要做的。
  • 如果你捕捉到一个你想要传递的特定异常,只需使用 throw; (它只是重新抛出异常)或 throw new MyException("Here is my error", innerException) (它创建一个新异常并使用 innerException 构建堆栈跟踪)。
【解决方案2】:

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

【讨论】:

  • 我认为这取决于语言。我确信在 Java 中您可以“链接”异常,这样在重新抛出时就不会丢失原始堆栈跟踪。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • C# 和 PHP 可以有多个 catch 块用于一个 try 块。
    【解决方案5】:

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

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

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

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

    【讨论】:

      【解决方案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.
      }
      

      【讨论】:

        【解决方案7】:

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-17
          • 1970-01-01
          • 1970-01-01
          • 2010-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-03
          相关资源
          最近更新 更多