80

我一直在我的 PHP 代码中使用 try..catch 块,但我不确定我是否正确使用了它们。

例如,我的一些代码如下所示:

 try {
      $tableAresults = $dbHandler->doSomethingWithTableA();
      $tableBresults = $dbHandler->doSomethingElseWithTableB();
 } catch (Exception $e) {
      return $e;
 }

所以我将多个数据库操作分组在同一个 try/catch 块中,因为如果任何事务中发生任何异常,我将能够处理它。

我这样做是因为我认为它比以下更具可读性和效率:

 try {
       $tableAresults = $dbHandler->doSomethingWithTableA();
 } catch (Exception $e) {
       return $e;
 }
 try {
       $tableBresults = $dbHandler->doSomethingWithTableB();
 } catch (Exception $e) {
       return $e;
 }

虽然,我不确定我正在做的是一种好的做法,还是只是一种捕捉异常的懒惰方式。

我的假设是,只有当异常需要特殊处理时,它才应该有自己的 try/catch 块,否则将它们分组在同一个 try/catch 中应该没问题。

所以我的问题是:

每个数据库事务使用 try/catch 块有什么好处吗?还是我仍然可以将多个数据库事务分组在同一个 try/catch 块中而完全没有问题?

可以嵌套 try/catch 块吗?谢谢!

编辑

return 语句主要仅用于演示目的,但我也使用 return incatch()因为我正在向该方法发出 AJAX 请求,并且 Javascript 需要一个 JSON 对象,然后如果发生异常,我将返回一个空的 JSON 编码数组. 我只是认为在我的示例中放置特定代码不会增加任何价值。

4

8 回答 8

92

重要的提示

下面的讨论假设我们讨论的代码结构如上例所示:无论选择哪个替代方案,异常都会导致该方法在逻辑上停止执行其中间的任何操作。


只要无论try块中的哪个语句引发异常,您都打算做同样的事情,那么使用单个try/肯定会更好catch。例如:

function createCar()
{
    try {
      install_engine();
      install_brakes();
    } catch (Exception $e) {
        die("I could not create a car");
    }
}

如果您可以并且打算以特定于确切原因的方式处理故障,则多个try/catch块很有用。

function makeCocktail()
{
    try {
        pour_ingredients();
        stir();
    } catch (Exception $e) {
        die("I could not make you a cocktail");
    }

    try {
        put_decorative_umbrella();
    } catch (Exception $e) {
        echo "We 're out of umbrellas, but the drink itself is fine"
    }
}
于 2013-07-09T13:35:49.003 回答
21

为了子孙后代,答案可能为时已晚。您应该检查变量的返回值并抛出异常。在这种情况下,您可以确保程序将从引发异常的地方跳转到 catch 块。在下面找到。

try{
   $tableAresults = $dbHandler->doSomethingWithTableA();
   if (!tableAresults) 
     throw new Exception('Problem with tableAresults');

  $tableBresults = $dbHandler->doSomethingElseWithTableB();
   if (!tableBresults) 
     throw new Exception('Problem with tableBresults');
} catch (Exception $e) {
    echo $e->getMessage();

}
于 2014-10-20T23:31:47.060 回答
10

单个 try catch 块更具可读性。如果识别出一种错误很重要,我建议自定义您的异常。

try {
  $tableAresults = $dbHandler->doSomethingWithTableA();
  $tableBresults = $dbHandler->doSomethingElseWithTableB();
} catch (TableAException $e){
  throw $e;
} catch (Exception $e) {
  throw $e;
}
于 2016-10-19T19:24:43.933 回答
7

没有理由反对将单个块用于多个操作,因为任何抛出的异常都会阻止在失败后执行进一步的操作。至少只要您可以从捕获的异常中得出哪个操作失败的结论。只要处理某些操作就可以了。

但是我想说返回异常的意义有限。函数的返回值应该是某些操作的预期结果,而不是异常。如果您需要对调用范围内的异常做出反应,那么要么不要在函数内部捕获异常,而是在调用范围内捕获异常,或者在完成一些调试日志等之后重新抛出异常以供以后处理。

于 2013-07-09T13:38:34.237 回答
6

当抛出异常时,执行立即停止并在catch{}块处继续。这意味着,如果将数据库调用放在同一个try{}块中并$tableAresults = $dbHandler->doSomethingWithTableA();引发异常,$tableBresults = $dbHandler->doSomethingElseWithTableB();则不会发生。使用您的第二个选项,$tableBresults = $dbHandler->doSomethingElseWithTableB();仍然会发生,因为它在catch{}块之后,当执行恢复时。

没有适合每种情况的理想选择;如果您希望第二次操作继续进行,那么您必须使用两个块。如果不发生第二个操作是可接受的(或可取的),那么您应该只使用一个。

于 2013-07-09T13:38:14.063 回答
1

在单个 try catch 块中,您可以做所有事情,如果您希望它们显示特定错误的自己的消息,则最佳实践是在不同的 catch 块中捕获错误。

于 2013-07-09T13:39:03.020 回答
1
try
{
    $tableAresults = $dbHandler->doSomethingWithTableA();
    if(!tableAresults)
    {
        throw new Exception('Problem with tableAresults');
    }
    $tableBresults = $dbHandler->doSomethingElseWithTableB();
    if(!tableBresults) 
    {
        throw new Exception('Problem with tableBresults');
    }
} catch (Exception $e)
{
    echo $e->getMessage();
}
于 2016-10-19T11:48:44.647 回答
0

使用单个 try catch 块编写多行执行没有任何问题,如下所示

try{
install_engine();
install_break();
}
catch(Exception $e){
show_exception($e->getMessage());
}

install_engine在函数中或函数中发生任何 execption 的那一刻install_break,控件将被传递给 catch 函数。另一个建议是正确地吃掉你的异常。die('Message')这意味着总是建议正确地进行异常处理,而不是编写。您可能会想到die()在错误处理中使用函数,而不是在异常处理中。

何时应该使用多个 try catch 块 如果您希望不同的代码块异常显示不同类型的异常,或者您试图从 catch 块中抛出任何异常,您可以考虑多个 try catch 块,如下所示:

try{
    install_engine();
    install_break();
    }
    catch(Exception $e){
    show_exception($e->getMessage());
    }
try{
install_body();
paint_body();
install_interiour();
}
catch(Exception $e){
throw new exception('Body Makeover faield')
}
于 2017-03-02T23:19:53.783 回答