Is it a good idea to only catch exceptions in production?
我继承了一个代码库,其中包含以下代码(注意:示例代码是php):
1 2 3 4 5 6 7 | try { // Do something which doesn't intentionally throw exceptions. } catch (\Exception $e) { $this->log->log($e->getMessage()); $this->product->setError($e->getMessage()); return false; } |
因此,从本质上讲,代码正在捕获异常。记录它,并且无提示地失败(除了日志消息)。
这种行为在生产中似乎很有意义,但使开发变得更加困难(因为堆栈跟踪必须在日志文件中查找,而不是打印到控制台)。因此,我提出了以下功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; } } } |
然后可以这样使用:
1 2 3 | $this->tryCatch(function () { // Do something }); |
此代码用于特殊情况下的"测试"环境,它调用传入函数而不进行异常处理(因此任何异常都将保持未处理状态)。在每个其他环境(例如生产环境)中,它将传入的闭包包装在生产环境中的try-catch块中,其行为与代码最初的行为相同。
这个解决方案解决了我的问题,但它似乎有点老土,让我对人工智能有一种不好的感觉。
我的问题是:我有什么理由不这样做吗?还是有更好的方法来处理这种情况?
不要试图在例外情况下重新发明轮子。有一个而且只有一个场景,在这个场景中,您应该排除一个例外:
如果你有一个可供选择的计划,那就抓住一个例外。
异常意味着您的代码遇到了一个异常情况,在这种情况下,它无法继续工作,除了放弃它别无选择。这是放弃函数/模块/执行上下文并向调用方发出更高级别的信号的一个非常好的方法。例外就是这样。
在开发过程中,您希望看到异常在所有丑陋的荣耀中都能够调试。在生产中,您不希望用户看到异常,而是向他们展示一个漂亮的错误屏幕和/或发出各种各样的铃声和哨声,通知管理员/开发人员/CTO/任何人。
这意味着,在生产环境中,您只需要一个全局错误处理程序,当发生意外的未捕获异常时,该处理程序会做出相应的响应。异常应该像开发中那样被抛出和捕获,您不需要两个完全独立的代码路径。这个全局错误处理程序可以通过一些只使用
您真正应该编写
1 2 3 4 5 6 7 8 9 | 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下载是一个预期的结果,可以很好地处理异常,因此这是一个很好的用例。但即使它们不能代表预期的结果,也不要自反地试图抓住它们。