编程中的异常处理机制

异常处理又称为错误处理,用来解决程序运行时出现的意外或异常情况。异常处理一般有两种模型,终止模型和恢复模型。

『终止模型』指在程序运行时只要异常被抛出就已无法挽回,程序将终止运行。『恢复模型』指程序运行出错之后能提供修正的方法,让程序继续执行。任何编程语言都是基于这两种模型处理异常。

恢复模型可以理解为常用的try catch,终止模型可以理解为项目中无法支配的神秘力量。所以不要认为程序员就能掌控程序,大多时候他们连异常都掌控不了。

终止模型会导致服务中断,没有重来的机会,解决办法是对日志做监控及时的叫醒程序员起床修复。恢复模型会给程序一次重来的机会,在面向对象的语言中实现方法大同小异,如下:

1
2
3
4
5
try{
// 可能抛出异常的语句
}catch(exceptionType variable){
// 处理异常的语句
}

try是“检测”的意思,用来检测语句块有没有异常,catch 是“抓住”的意思,用来捕获并处理 try 检测到的异常。如果 try 语句块没有检测到异常,那么就不会执行 catch 中的语句。说的有点拗口,简单点说:

try是法律,catch是警察。要是在法律的规定下违法了,警察会抓人(如果违反了交规,就需要交警去抓,catch的参数也很重要)。如果遵纪守法,警察就不会出现。

接下来看看JAVA和PHP的异常处理机制。

Java异常处理机制

Java的异常处理机制非常完善,是行业五星项目,无论你喜不喜欢都要学习他的异常处理。因为Java需要将代码编译成二进制码,所以Java的异常类型也分为两种,Checked Exception 和 Unchecked Exception。

Checked Exception指编译时检查是否加了异常判断,比如写了IO操作但没有检测IO异常(IOException)会提示编译错误。自定义的Exception都应该是Checked Exception,以便于最大化利用Java编译器的编译时检查。

Unchecked Exception指编译时不检查的异常,Unchecked Exception又分为可捕获的异常和无法捕获的异常。比如空指针异常(NullPointerException)就是可捕获的异常。Error就是无法捕获的异常,会导致程序终止。如下图:

Checked-and-Unchecked-Exceptions-in-Java

PHP的异常处理

相比Java,PHP的异常处理就有些山寨,早期的PHP不支持面向对象编程,到PHP5才引入了面向对象的相关语法。所以异常处理是PHP的错误处理系统向面向对象演进后的产物。

Java在编译时会检测Checked Exception,不处理编译无法通过。PHP少了编译的步骤,所以无法原生的实现对异常的检测。好在我们可以通过第三方工具去检测异常的处理,比如利用编辑器的提示功能,在gitlab中集成代码检测功能等。虽然是曲线救国,但也算朝着标准在努力。

我曾经看到有开发人员直接给入口函数加try catch,将整个请求都包裹起来就是非常糟糕的做法,这样做不但会影响程序的性能还会将一些应该暴露的问题隐藏。

很多开发者不清楚什么时候该用try catch。按正常的开发规范,应该检查调用的函数是否会抛出异常(主流的编辑器都有提示功能),然后进行相应的处理,尤其是使用第三方编写的PHP组件和框架时。比如调用PHP的file_get_contents函数时就可能返回异常,所以使用file_get_contents要加try catch

PHP异常处理相关配置

PHP提供了灵活的异常处理配置,很方便进行开发调试,对生产环境的未知错误做预警等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
;显示错误
display_startup_errors = On
display_errors = On

;报告所有错误
error_reporting = -1

;记录错误
log_errors = On
在生产环境中设置 php.ini 文件的错误报告方式如下:

;不显示错误
display_startup_errors = Off
display_errors = Off

;除了notice级别错误外,报告所有其他错误
error_reporting = E_ALL & ~E_NOTICE

;记录错误
log_errors = On
如果生产环境有缺陷,我们一般通过查看 PHP 错误日志来定位问题。

推荐一个PHP的错误展示包,可通过composer直接安装。

1
2
//使用文档可直接查看扩展包的readme文件
composer require filp/whoops --dev

最后

预测、捕获、处理异常是程序员的责任,不要因为觉得麻烦就不处理。未捕获的异常会导致应用终止运行,暴露敏感信息。都看到这里了,关注个公众号吧。