How to efficiently use try…catch blocks in PHP
我在PHP代码中使用了try..catch块,但我不确定是否正确使用了它们。
例如,我的一些代码如下:
1 2 3 4 5 6 | try { $tableAresults = $dbHandler->doSomethingWithTableA(); $tableBresults = $dbHandler->doSomethingElseWithTableB(); } catch (Exception $e) { return $e; } |
所以我将多个数据库操作分组在同一个try/catch块中,因为如果在任何事务中发生任何异常,我都可以处理它。
我这样做是因为我认为它比:
1 2 3 4 5 6 7 8 9 10 | 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语句主要是为了演示,但我也在
重要注意事项
下面的讨论假设我们正在讨论的代码结构与上面的示例相同:无论选择哪种替代方法,异常都会导致方法在逻辑上停止执行中间的任何操作。
只要您打算做同样的事情,不管
1 2 3 4 5 6 7 8 9 | function createCar() { try { install_engine(); install_brakes(); } catch (Exception $e) { die("I could not create a car"); } } |
如果您能够并打算以特定于具体原因的方式处理故障,那么多个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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" } } |
为了子孙后代着想,答案可能太晚了。您应该检查变量的返回值并抛出异常。在这种情况下,您可以确保程序将从引发异常的位置跳转到catch块。在下面找到。
1 2 3 4 5 6 7 8 9 10 11 12 | 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(); } |
在一个try-catch块中,它的可读性更高。如果重要的是识别一种错误,我建议您自定义异常。
1 2 3 4 5 6 7 8 | try { $tableAresults = $dbHandler->doSomethingWithTableA(); $tableBresults = $dbHandler->doSomethingElseWithTableB(); } catch (TableAException $e){ throw $e; } catch (Exception $e) { throw $e; } |
没有理由不将单个块用于多个操作,因为任何引发的异常都将阻止在失败的操作之后执行进一步的操作。至少只要您能断定哪个操作因捕获的异常而失败。只要不处理某些操作就可以。
不过,我想说,返回异常情况的意义有限。函数的返回值应该是某些操作的预期结果,而不是异常。如果您需要对调用范围中的异常作出反应,那么要么在函数内部的此处不捕获异常,而是在调用范围中捕获异常,要么在完成一些调试日志记录等之后重新抛出异常以供以后处理。
当抛出异常时,立即停止执行,并在
对于每种情况都没有理想的选择;如果您希望第二个操作无论如何都继续,则必须使用两个块。如果不执行第二个操作是可以接受的(或可取的),那么应该只使用一个操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } |
在一个try-catch块中,您可以做所有的事情,如果您希望不同的catch块中的错误显示为特定错误的消息,那么最佳实践是捕获它们。
用下面这样的一个try-catch块编写多行执行没有任何问题
1 2 3 4 5 6 7 | try{ install_engine(); install_break(); } catch(Exception $e){ show_exception($e->getMessage()); } |
在
当应该使用多个try catch块时如果希望不同的代码块异常显示不同类型的异常,或者试图从catch块中抛出任何异常,可以考虑使用多个try catch块,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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') } |
有关如何在不同情况下使用Try-Catch块的详细信息,请参阅我在php上的博客Try-Catch。