我继承了一个代码库,其中包含如下代码(注意:示例代码是 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 
}); 

此代码对它调用传入函数而不进行异常处理的“测试”环境进行了特殊处理(因此任何异常都保持未处理)。在所有其他环境(例如生产环境)中,它将传入的闭包包装在 try-catch block 中,生产环境的行为与代码最初的行为相同。

这个解决方案解决了我的问题,但它似乎有点老套,让我觉得这不是一个好主意。

我的问题:有什么理由我不应该这样做吗?或者有没有更好的方法来处理这种情况?

请您参考如下方法:

不要试图在异常方面重新发明轮子。您应该在一种情况下catch一个异常(exception):

捕获异常 如果您有替代计划该怎么办。

异常意味着您的代码遇到了异常情况,在这种情况下它无法继续工作,别无选择,只能认输。这是放弃函数/模块/执行上下文并向更高层的调用者发出信号的一种非常好的方法。这正是异常所做的。

在开发过程中,您希望看到异常的所有丑陋荣耀,以便能够进行调试。在生产中,您不希望您的用户看到异常,而是向他们展示一个漂亮的错误屏幕和/或让各种花里胡哨的声音通知管理员/开发人员/CTO/任何人。

这意味着,在生产中您只需要 一个全局错误处理程序 如果发生意外的、未捕获的异常,它会做出适当的响应。应该像在开发中一样抛出和(不)捕获异常,您不想要两个完全独立的代码路径。这个全局错误处理程序可以通过一些引导脚本有条件地设置,只需使用 set_exception_handler ;或者可能更好,你 配置您的网络服务器适本地提供有用的错误页面。配置 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 下载失败是预期结果,可以很好地处理异常,因此这是一个很好的用例。但是,即使它们不代表预期的结果,也不要条件反射地试图捕获它们。


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!