
PHP 类中统一捕获异常:用 try-catch 不够,得靠 set_exception_handler
类内部无法靠 try-catch 捕获所有错误——它只管自己写的那几行。真正想“统一处理”,得跳出类的边界,用全局钩子。
PHP 提供 set_exception_handler(),它会在任何未被捕获的 Exception(或继承自它的类)抛出时触发,且优先级高于类内逻辑。这个函数必须在脚本早期注册,比如入口文件(index.php)顶部,否则中间抛出的异常就漏掉了。
- 不能在类构造函数里调用
set_exception_handler()—— 它是全局行为,不是实例方法 - 传给它的回调函数可以是静态方法:
[$class, 'handleException'],但该方法必须是public static - 注意:它不处理
Error(如ParseError、FatalError),PHP 7+ 需额外配set_error_handler()或用set_exception_handler()+Throwable类型提示兼容
类中主动触发统一错误处理:throw 新异常,别直接 echo/die
很多人在类方法里遇到问题就写 echo "失败"; die();,这等于放弃控制权——没法记录、没法返回结构化响应、没法被上层统一拦截。
正确做法是:把错误转化为异常,交给外部兜底。哪怕只是业务校验失败,也该 throw new RuntimeException("用户名不能为空")。
立即学习“PHP免费学习笔记(深入)”;
v1.13更新:1.增加产品讨论功能(ProductMsg备注字段)2.修正页面中的js错误数处。3.删除后的拍卖产品在回收站中统一管理。4.版面图标的DIY..自己更换,表格颜色自由调配。5.无限分类结构优化。6.产品说明支持HTML.7.网页界面优化.8.修正产品上下跳转的条数错误。9.完善邮件群发功能,可选择发送给不同类型的商城用户。10.修正拍卖信息中错误的交易完成Bug。11.去掉搜索用
- 避免用
trigger_error(),它走的是传统错误机制,和Exception体系不互通 - 自定义异常类建议继承
RuntimeException(逻辑错误)或InvalidArgumentException(参数问题),便于外部按类型区分处理 - 如果类本身要封装错误上下文(如请求 ID、用户 ID),可以在异常构造时传入,而不是拼接进消息字符串
__destruct 中不能 throw 异常:这是最常踩的坑
PHP 明确规定:析构函数 __destruct() 内抛出的异常会被静默忽略,甚至可能引发致命错误(Fatal error: Exception thrown without a stack frame)。
这意味着,如果你在类销毁时做清理(比如关闭远程连接、写日志),出错了绝不能 throw。必须降级为日志记录或静默失败。
- 不要在
__destruct()里调用可能抛异常的方法,除非你已用try-catch包住并吞掉异常 - 需要确保执行的清理动作,优先选不会抛异常的替代方案(例如用
fclose()而非依赖某个封装类的close()方法) - 如果真有不可忽略的销毁失败(如缓存写入失败),应在业务逻辑结束前显式调用
cleanup()方法,而非等自动析构
错误级别与日志联动:别只靠 display_errors
开发环境开 display_errors = On 看报错,上线后关掉就以为万事大吉?不是的。很多错误(尤其是 Notice、Warning)默认不进异常体系,却可能暴露敏感路径或导致逻辑偏移。
统一处理错误,得让这些传统错误也进日志管道。用 set_error_handler() 把它们转成异常或直接记录:
set_error_handler(function($level, $message, $file, $line) {
if (!(error_reporting() & $level)) return;
error_log("[{$level}] {$message} in {$file}:{$line}");
// 可选:throw new ErrorException($message, 0, $level, $file, $line);
});
-
error_reporting()的值会影响set_error_handler()是否被调用,务必检查当前环境配置 - Notice 级别错误在严格模式下容易被忽略,但可能预示变量未定义、数组键不存在等隐患
- 日志路径最好用绝对路径,避免因工作目录变化导致写入失败(如写到
/tmp/php-error.log而不是./logs/error.log)









