如何在 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_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')
【讨论】:
以上是关于如何在 PHP 中有效地使用 try...catch 块的主要内容,如果未能解决你的问题,请参考以下文章