在开发过程中,错误、异常的暴露及处理不可避免。

合理地暴露错误和抛出异常,是提升开发效率的一大法门。

潜在的问题对应的修正成本,会随着项目的迭代不断上升;因此,尽早暴露问题,尽早解决问题,是对整个工程的负责。那么在开发过程中,如何尽早的暴露问题,并解决?暴露问题后速度迅速的定位问题,并修正?生产环境中又该作哪些处理?

  1. 采用严格模式。暴露包括 warning 级别在内的问题,使代码更加规范。
  2. 使用断言。提前对变量/数据进行有效性要求,及时抛出错误;也可避免应用层永无止境的合法性判断需求。
  3. 格式化的错误信息和统一化的错误处理通道。原始的错误信息,对开发人员来说,有时候未必友好。如在Web中阅读原始错误信息可能不便,需要对其加上相应的HTML标签;在客户端限定返回数据为json格式时,裸信息会被视为非法数据,因此也需要格式化。
  4. 开发模式下,应该尽可能地往简洁有效(即不要带上无关信息)/详细(该有的信息量一定要有)/可读性强(友好阅读,一目了然)三个方面因地制宜地去格式化。
  5. 生产环境下,同理,要返回普通用户可读的错误信息。

在 PHP 中,「错误」和「异常」存在一些区别。

「错误」可以看做是无意的、被动的行为,如代码中出现了 a = 1 / 0; 这类使开发/运行环境无法编译/解释的语句,就会报出一个错误。

「异常」可以理解为是开发者主动抛出的。比如在程序中,判断用户登录状态,如果 token 过期,就在其条件分支处主动抛一个 token 过期 的异常。

某个请求中,出现错误和异常,可能会直接回显(如果开启了相应配置),这么一来可能会影响返回数据格式的合法性。因此,科学地进行调试,需要做到几点:

  1. 统一的请求出口。出口中包含对异常的捕捉,保证所有的请求,即使发生错误,也一定要返回值,返回格式是合法的。
  2. 让错误的抛出可控。因为错误并非主动抛出,开发者无法预知何处会出现错误;所以在这里可以通过 set_error_handler 方法,对错误做统一的处理,如在方法中抛出异常(异常中要包含错误相关的信息量)。
  3. 异常是主动抛出的,可直接在应用层中 catch;也可以通过 set_exception_handler 方法,对它进行统一处理。
  4. 其实以上两点,只有一个目的:就是在一个请求中,只在规定的地方回显字符,避免因错误/异常的被动回显,保证返回数据格式的正确性

error_reporting() 范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

// 关闭所有PHP错误报告
error_reporting(0);

// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// 报告 E_NOTICE也挺好 (报告未初始化的变量
// 或者捕获变量名的错误拼写)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);

// 除了 E_NOTICE,报告其他所有错误
// 这是在 php.ini 里的默认设置
error_reporting(E_ALL ^ E_NOTICE);

// 报告所有 PHP 错误 (参见 changelog)
error_reporting(E_ALL);

// 报告所有 PHP 错误
error_reporting(-1);

// 和 error_reporting(E_ALL); 一样
ini_set('error_reporting', E_ALL);
1
ini_set('error_log','/dev/null');

实践使用待整理……

参考链接