如何有效地使用PHP中的try…catch块


78

我在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,catch()因为我正在对该方法发出AJAX请求,而Javascript期望使用JSON对象,那么如果发生异常,我将返回一个空的JSON编码数组。我只是认为它不会为在示例中添加特定代码带来任何价值。


我有相同的答案。这取决于! 数据库事务是相互依赖的FOREIGN KEYS吗?表B中的交易是否取决于表A中的交易?这就是您需要问自己决定是否可以将它们分组的内容。
CodeAngry

是的,表B中的事务取决于表A中的事务。因此,如果transactionA失败,则transactionB不应该运行。它可以运行,但是无论如何都会返回一个空的结果集。
ILikeTacos 2013年

6
然后将它们分组!但是请记住,您需要了解执行此操作的原因和原因。只是这样想……一旦抛出,我是否需要下一行代码来执行?如果我不这样做,请将其放在try{}块中。我所做的...catch(){}结束后继续。
CodeAngry 2013年

Answers:


90

重要的提示

下面的讨论假定我们正在讨论如上例中所示的结构化代码:无论选择哪种选择,异常都将导致该方法在逻辑上停止执行中间的操作。


只要您打算做同样的事情,无论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"
    }
}

4
不要忘记PHP5.5添加了对finally
Mike Mackintosh的

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();

}

9

单个try catch块更具可读性。如果重要,请确定一种错误,建议您自定义例外。

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

7

没有理由不使用单个块来执行多个操作,因为任何抛出的异常都会阻止在失败的操作之后执行进一步的操作。至少只要您可以从捕获的异常中推断出哪个操作失败即可。只要不执行某些操作就可以。

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


6

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

对于每种情况都没有理想的选择。如果无论如何都希望第二个操作继续进行,则必须使用两个块。如果可以接受(或希望)不进行第二次操作,则应仅使用一个。



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();
}

0

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

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

当执行在函数中install_engineinstall_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')
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.