Php catch语句中函数的错误处理
这是一段代码,我想知道是否应该对其进行重构,使其更符合干净的代码实践 这是一个负责退还客户订单的课程Php catch语句中函数的错误处理,php,oop,zend-framework,error-handling,dry,Php,Oop,Zend Framework,Error Handling,Dry,这是一段代码,我想知道是否应该对其进行重构,使其更符合干净的代码实践 这是一个负责退还客户订单的课程 class RefundServiceInvoker { private $_orders; public function refundOrder() { $this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders fore
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders
foreach ($this->_orders as $order) {
try {
$order->refund(); //Some lines may throw an exception when refunded due to some business logic (ex. the order was already shipped)
$this->updateOrderStatus('refunded')
} catch (Exception $e) {
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
}
当然,这段代码比我的原始代码要简单得多
我的主要问题是如果$order->return()代码>引发异常,它将被捕获并记录到数据库,然后发送邮件。但是如果$this->logError($e)代码>本身引发异常?或者如果邮件服务器关闭并引发异常怎么办
如果数据库本身关闭并且$this->getOrdersFromDB()代码>引发异常
我的第一个解决方案是将所有内容包装在一个大的try{}catch{}
:
public function refundOrder() {
try {
$this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders
foreach ($this->_orders as $order) {
$order->refund(); //Some lines may throw an exception when refunded due to some business logic (ex. the order was already shipped)
$this->updateOrderStatus('refunded')
} catch (Exception $e) {
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
但这意味着如果一个订单失败,那么所有订单都会失败!!我应该为整个函数放置2try{}catch{}
一个,为每个顺序放置另一个吗?但是在这种情况下,catch中的函数也可能抛出一个不会被捕获的异常
注:
该应用程序是使用Zend framework 1.11.11构建的
提前感谢。解决这些问题没有灵丹妙药。如果一个函数可以抛出,而您关心它,那么您必须围绕它包装try
/catch
——就这么简单
进入细节:在没有更多关于应用程序架构的信息的情况下,评估这种或那种方法的优点是不可能的,但这里有一些一般性的建议:
- 在致电
退款订单
之前检查先决条件。确保订单已成功加载;确保您要操作的订单都是可退款的(尝试退款由于业务逻辑而不可退款的订单的目的是什么?在尝试退款之前不应该通知用户/运营商吗?)
- 不要使用多个级别的
尝试/捕获
,但可能不是所有的退款订单
。外部块用于捕获任何真正意外的错误,那么仅在returnorder
内部捕获它们有什么意义呢?你不想在应用程序的其他部分也这样做吗?最里面的try
/catch
是必需的,这样一个不可退款的订单就不会终止整个流程
解决这些问题没有灵丹妙药。如果一个函数可以抛出,而您关心它,那么您必须围绕它包装
try
/catch
——就这么简单
进入细节:在没有更多关于应用程序架构的信息的情况下,评估这种或那种方法的优点是不可能的,但这里有一些一般性的建议:
- 在致电
退款订单
之前检查先决条件。确保订单已成功加载;确保您要操作的订单都是可退款的(尝试退款由于业务逻辑而不可退款的订单的目的是什么?在尝试退款之前不应该通知用户/运营商吗?)
- 不要使用多个级别的
尝试/捕获
,但可能不是所有的退款订单
。外部块用于捕获任何真正意外的错误,那么仅在returnorder
内部捕获它们有什么意义呢?你不想在应用程序的其他部分也这样做吗?最里面的try
/catch
是必需的,这样一个不可退款的订单就不会终止整个流程
由于logError($e)
和sendMailToAdmin()
可能是在最后手段中使用的函数,通常在try/catch块中,我会确保它们不会引发异常
function logError($e)
{
try
{
//your logic that may throw an Exception here
}
catch {}
}
function sendMailToAdmin($e)
{
try
{
//your logic that may throw an Exception here
}
catch {}
}
由于logError($e)
和sendMailToAdmin()
可能是在最后手段中使用的函数,通常在try/catch块中使用,因此我将确保它们不会引发异常
function logError($e)
{
try
{
//your logic that may throw an Exception here
}
catch {}
}
function sendMailToAdmin($e)
{
try
{
//your logic that may throw an Exception here
}
catch {}
}
如果您需要记录并邮寄每个异常,那么您需要以下内容:
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
try {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
} catch(Exception $e) {
# deals with unexpected bugs
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
}
}
但您必须在log和mail方法中加入try/catch,以防止它们在服务器脱机时抛出任何异常。如果不这样做,当日志/邮件失败时,$orders循环将停止
如果您只需要在return()方法中记录/发送您的业务异常,那么您需要如下内容:
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
try {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
} catch(Exception $e) {
# deals with unexpected bugs
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
}
}
任何其他异常都会导致http 500–内部服务器错误页面,这通常是您想要的,因为这是一个意外错误
还有其他方法可以处理此问题,但正如您所看到的,这取决于您的需要。如果您需要记录并邮寄每个异常,那么您需要以下内容:
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
try {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
} catch(Exception $e) {
# deals with unexpected bugs
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
}
}
但您必须在log和mail方法中加入try/catch,以防止它们在服务器脱机时抛出任何异常。如果不这样做,当日志/邮件失败时,$orders循环将停止
如果您只需要在return()方法中记录/发送您的业务异常,那么您需要如下内容:
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
try {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
} catch(Exception $e) {
# deals with unexpected bugs
$this->logError($e);
$this->sendMailToAdmin();
}
}
}
class RefundServiceInvoker {
private $_orders;
public function refundOrder() {
$this->getOrdersFromDB();
foreach ($this->_orders as $order) {
try {
$order->refund();
} catch (MyBusinessException $e) {
# deals with the problematic $order without stopping the loop
$this->logError($e);
$this->sendMailToAdmin();
}
$this->updateOrderStatus('refunded');
}
}
}
任何其他异常都会导致http 500–内部服务器错误页面,这通常是您想要的,因为这是一个意外错误
还有其他方法可以处理这个问题,但正如您所看到的,这取决于您的需要。是否$this->logError()
确实引发过异常?看起来这可能不是最佳实践,您可能很容易陷入无限循环。您真正需要做的是决定如果错误日志记录/管理电子邮件发送失败,您希望应用程序做什么。如果您只是忽略错误并继续,请不要抛出这些方法中的任何异常。如果您希望使用堆栈跟踪终止,请不要捕获异常。如果你想知道如何处理这种情况,可以使用内部的try/catch。嗯…基本上是的,