只捕获生产中的异常是个好主意吗?
Is it a good idea to only catch exceptions in production?
我继承了一个代码库,其中包含如下代码(注意:示例代码是 PHP):
try {
// Do something which doesn't intentionally throw exceptions.
} catch (\Exception $e) {
$this->log->log($e->getMessage());
$this->product->setError($e->getMessage());
return false;
}
所以本质上,代码正在捕获异常。记录它,并默默地失败(除了日志消息)。
这种行为在生产中似乎有意义,但使开发变得更加困难(因为堆栈跟踪必须在日志文件中查找,而不是打印到控制台)。所以我想出了以下功能:
private function tryCatch ($func) {
// Bind closure, so that $this allows it to access class properties
if (is_object($func) && ($func instanceof Closure)) {
\Closure::bind($func, $this, "static");
}
if (\App::environment('test')) {
return $func();
} else {
try {
return $func();
} catch (\Exception $e) {
$this->log->log($e->getMessage());
$this->product->setError($e->getMessage());
return false;
}
}
}
然后可以像这样使用:
$this->tryCatch(function () {
// Do something
});
此代码对 'test' 环境进行特殊处理,它调用传入的函数而不进行异常处理(因此任何异常都未处理)。在所有其他环境中(例如生产环境),它将传入的闭包包装在生产中的 try-catch 块中,其行为与代码最初的行为相同。
这个解决方案解决了我的问题,但它似乎有点老套,让我觉得这不是一个好主意。
我的问题:我有什么理由不应该这样做吗?或者有更好的方法来处理这种情况吗?
不要试图在异常方面重新发明轮子。只有一种情况你应该 catch
例外:
捕获异常如果您有其他计划如何处理它。
异常意味着您的代码遇到了异常情况,在这种情况下它无法继续工作并且别无选择,只能认输。这是放弃 function/module/execution 上下文并向更高层的调用者发出发生了什么的信号的完美方式。这正是异常的作用。
在开发过程中,您希望看到异常的所有丑陋之处以便能够进行调试。在生产中,您 不 希望您的用户看到异常,而是向他们展示一个漂亮的错误屏幕 and/or =49=].
这意味着,在生产环境中,您只需要 一个全局错误处理程序,它会在 意外的、未捕获的 异常发生时做出适当的响应。应该像在开发中一样抛出和(不)捕获异常,您不希望有两个完全独立的代码路径。这个全局错误处理程序可以通过一些引导脚本有条件地设置,只需使用 set_exception_handler
;或者甚至更好,您 适当地配置您的 Web 服务器 以提供有用的错误页面。配置 Web 服务器是最好的方法,因为这是系统特定的设置(仅限生产),无需更改任何代码。
您真正应该编写 try..catch
的唯一情况是子系统可能出现故障并且您有备份计划的正当理由。例如:
try {
$file = download_file_from_url($url);
echo "Cool, got your file.";
} catch (HttpNotFound $e) {
echo "Hey user, that file doesn't exist.";
} catch (HttpEmptyResponse $e) {
echo "Hey user, that file seems empty.";
}
..
在这种情况下,失败的 HTTP 下载是预期结果并且可以很好地处理异常,因此这是一个很好的用例。但不要反射性地试图 全部抓住它们 即使它们不代表 预期结果 .
我继承了一个代码库,其中包含如下代码(注意:示例代码是 PHP):
try {
// Do something which doesn't intentionally throw exceptions.
} catch (\Exception $e) {
$this->log->log($e->getMessage());
$this->product->setError($e->getMessage());
return false;
}
所以本质上,代码正在捕获异常。记录它,并默默地失败(除了日志消息)。
这种行为在生产中似乎有意义,但使开发变得更加困难(因为堆栈跟踪必须在日志文件中查找,而不是打印到控制台)。所以我想出了以下功能:
private function tryCatch ($func) {
// Bind closure, so that $this allows it to access class properties
if (is_object($func) && ($func instanceof Closure)) {
\Closure::bind($func, $this, "static");
}
if (\App::environment('test')) {
return $func();
} else {
try {
return $func();
} catch (\Exception $e) {
$this->log->log($e->getMessage());
$this->product->setError($e->getMessage());
return false;
}
}
}
然后可以像这样使用:
$this->tryCatch(function () {
// Do something
});
此代码对 'test' 环境进行特殊处理,它调用传入的函数而不进行异常处理(因此任何异常都未处理)。在所有其他环境中(例如生产环境),它将传入的闭包包装在生产中的 try-catch 块中,其行为与代码最初的行为相同。
这个解决方案解决了我的问题,但它似乎有点老套,让我觉得这不是一个好主意。
我的问题:我有什么理由不应该这样做吗?或者有更好的方法来处理这种情况吗?
不要试图在异常方面重新发明轮子。只有一种情况你应该 catch
例外:
捕获异常如果您有其他计划如何处理它。
异常意味着您的代码遇到了异常情况,在这种情况下它无法继续工作并且别无选择,只能认输。这是放弃 function/module/execution 上下文并向更高层的调用者发出发生了什么的信号的完美方式。这正是异常的作用。
在开发过程中,您希望看到异常的所有丑陋之处以便能够进行调试。在生产中,您 不 希望您的用户看到异常,而是向他们展示一个漂亮的错误屏幕 and/or =49=].
这意味着,在生产环境中,您只需要 一个全局错误处理程序,它会在 意外的、未捕获的 异常发生时做出适当的响应。应该像在开发中一样抛出和(不)捕获异常,您不希望有两个完全独立的代码路径。这个全局错误处理程序可以通过一些引导脚本有条件地设置,只需使用 set_exception_handler
;或者甚至更好,您 适当地配置您的 Web 服务器 以提供有用的错误页面。配置 Web 服务器是最好的方法,因为这是系统特定的设置(仅限生产),无需更改任何代码。
您真正应该编写 try..catch
的唯一情况是子系统可能出现故障并且您有备份计划的正当理由。例如:
try {
$file = download_file_from_url($url);
echo "Cool, got your file.";
} catch (HttpNotFound $e) {
echo "Hey user, that file doesn't exist.";
} catch (HttpEmptyResponse $e) {
echo "Hey user, that file seems empty.";
}
..
在这种情况下,失败的 HTTP 下载是预期结果并且可以很好地处理异常,因此这是一个很好的用例。但不要反射性地试图 全部抓住它们 即使它们不代表 预期结果 .