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

我一直在 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()中的 return,因为我对这个方法发出了一个 AJAX 请求,并且 Javascript 希望得到一个 JSON 对象,那么如果发生异常,我将返回一个空的 JSON 编码的数组。我只是认为在我的例子中放置特定的代码不会增加任何价值。

121854 次浏览

重要提示

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


无论 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"
}
}

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

不存在适用于每种情况的理想选项; 如果您希望第二个操作无论如何都要继续,那么必须使用两个块。如果不进行第二次操作是可以接受的(或者可取的) ,那么您应该只使用一次操作。

没有理由反对对多个操作使用单个块,因为任何抛出的异常都会阻止在失败的操作之后执行进一步的操作。至少只要您能够从捕获的异常中判断出哪个操作失败。如果某些操作是 没有处理的,那么只要没有问题就可以。

然而,我认为返回异常的意义有限。函数的返回值应该是某个操作的预期结果,而不是异常。如果您需要对调用范围中的异常作出反应,那么要么不捕获函数中的异常,而是在调用范围中捕获异常,要么在执行了一些调试日志记录等操作之后重新抛出异常,以便以后处理。

在一个 try catch 块中,你可以做所有的事情最好的做法是在不同的 catch 块中捕获错误,如果你想让它们显示特定错误的消息。

为了子孙后代,这个答案可能太迟了。您应该检查变量的返回值并引发异常。在这种情况下,可以确保程序将从引发异常的地方跳转到 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
{
$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;
}

如下所示,使用一个 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')
}