如何在 PHP 中有效地使用 try...catch 块

Posted

技术标签:

【中文标题】如何在 PHP 中有效地使用 try...catch 块【英文标题】:How to efficiently use try...catch blocks in PHP 【发布时间】:2013-07-07 03:21:26 【问题描述】:

我一直在我的 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 语句主要仅用于演示目的,但我也在 catch() 中使用返回,因为我正在向该方法发出 AJAX 请求,并且 javascript 需要一个 JSON 对象,那么如果发生异常我返回一个空的 JSON 编码数组。我只是认为在我的示例中放置特定代码不会增加任何价值。

【问题讨论】:

我也有同样的答案。 这取决于! 数据库事务是否相互依赖,FOREIGN KEYS 是否涉及?表 B 中的事务是否依赖于表 A 中的事务? 这就是你需要问自己来决定是否可以对它们进行分组。 是的,表 B 中的事务依赖于表 A 中的事务。因此,如果事务 A 失败,则事务 B 不应该运行。它可以运行,但无论如何它都会返回一个空的结果集。 然后将它们分组! 但请记住,您需要了解您这样做的目的和原因。像这样想... 一旦我抛出,我是否需要执行下一行代码? 如果不需要,请将它们放在try 块中。我所做的……在catch() 结束后继续。 【参考方案1】:

重要提示

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


只要你打算做同样的事情不管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"
    

【讨论】:

别忘了 PHP5.5 增加了对finally的支持【参考方案2】:

为了后代,答案可能为时已晚。您应该检查变量的返回值并抛出异常。在这种情况下,您可以确保程序将从引发异常的地方跳转到 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();


【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:
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();

【讨论】:

【参考方案8】:

用一个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')

【讨论】:

以上是关于如何在 PHP 中有效地使用 try...catch 块的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 和 MySQL 有效地对大型数据集进行分页?

php7新特新

如何使用 PHP 安全地将 JSON 数据写入文件

如何有效地从 php 中的平面结构构建树?

java中的异常

使用 PHP 有效地使用 Google App Engine 发送大量电子邮件?