我在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()中使用RETURNS,因为我对该方法发出了Ajax请求,而javascript期望得到一个JSON对象,那么如果发生异常,我将返回一个空的JSON编码数组。我只是认为在我的示例中放入特定的代码不会增加任何值。
我有同样的答案。这要看情况!DB交易是否相互依赖,是否涉及FOREIGN KEYS?表B中的事务是否依赖于表A中的事务?这就是你需要问自己决定是否可以将他们分组的问题。
是的,表B中的事务依赖于表A中的事务。因此,如果Transactiona失败,则TransactionB不应运行。它可以运行,但无论如何它都会返回一个空的结果集。
那就分组吧!但要记住,你需要理解你在做什么,为什么要做。就这样想…一旦抛出,是否需要执行下一行代码?如果我不这样做,就把它们放在try{}块。我做的那些…在catch(){}结束后继续。
重要注意事项
下面的讨论假设我们正在讨论的代码结构与上面的示例相同:无论选择哪种替代方法,异常都会导致方法在逻辑上停止执行中间的任何操作。
只要您打算做同样的事情,不管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的支持
为了子孙后代着想,答案可能太晚了。您应该检查变量的返回值并抛出异常。在这种情况下,您可以确保程序将从引发异常的位置跳转到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();
}
在一个try-catch块中,它的可读性更高。如果重要的是识别一种错误,我建议您自定义异常。
try {
$tableAresults = $dbHandler->doSomethingWithTableA();
$tableBresults = $dbHandler->doSomethingElseWithTableB();
} catch (TableAException $e){
throw $e;
} catch (Exception $e) {
throw $e;
}
没有理由不将单个块用于多个操作,因为任何引发的异常都将阻止在失败的操作之后执行进一步的操作。至少只要您能断定哪个操作因捕获的异常而失败。只要不处理某些操作就可以。
不过,我想说,返回异常情况的意义有限。函数的返回值应该是某些操作的预期结果,而不是异常。如果您需要对调用范围中的异常作出反应,那么要么在函数内部的此处不捕获异常,而是在调用范围中捕获异常,要么在完成一些调试日志记录等之后重新抛出异常以供以后处理。
当抛出异常时,立即停止执行,并在catch{}块继续执行。这意味着,如果将数据库调用放在同一个try{}块中,而$tableAresults = $dbHandler->doSomethingWithTableA();抛出异常,则不会发生$tableBresults = $dbHandler->doSomethingElseWithTableB();。第二种选择是,当执行恢复时,$tableBresults = $dbHandler->doSomethingElseWithTableB();仍然会发生,因为它在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();
}
在一个try-catch块中,您可以做所有的事情,如果您希望不同的catch块中的错误显示为特定错误的消息,那么最佳实践是捕获它们。
用下面这样的一个try-catch块编写多行执行没有任何问题
try{
install_engine();
install_break();
}
catch(Exception $e){
show_exception($e->getMessage());
}
在install_engine或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')
}
有关如何在不同情况下使用Try-Catch块的详细信息,请参阅我在php上的博客Try-Catch。