PHP未捕获异常默认返回500错误;Exception子类可用try-catch捕获,FatalError等需set_error_handler+register_shutdown_function兜底;全局处理器须在入口文件顶部注册;错误转异常应按error_reporting级别过滤;日志需包含请求、用户、参数等上下文。

PHP中未捕获异常会直接导致500错误
默认情况下,PHP遇到未被 try...catch 捕获的异常(如 RuntimeException、自定义异常),或致命错误(如 Fatal error: Call to undefined function),Web服务器会返回HTTP 500响应,页面空白,且错误细节通常不显示给用户——但也不会自动记录,极易掩盖问题。
关键不是“能不能捕获”,而是“哪些能捕获、哪些必须换方式处理”:
-
Exception及其子类(包括ErrorException)可用try...catch捕获 -
ParseError、FatalError等致命错误无法用try...catch捕获,需靠set_error_handler()+register_shutdown_function()组合兜底 -
TypeError、ArgumentCountError在 PHP 7+ 属于Throwable,可统一用catch (Throwable $e)
全局异常处理器必须注册在入口文件最顶部
很多开发者把 set_exception_handler() 放在某个类初始化之后,结果早期启动阶段(如配置加载、自动加载失败)抛出的异常根本进不去处理器。它必须在任何业务逻辑执行前就位。
典型安全写法(以 index.php 为例):
立即学习“PHP免费学习笔记(深入)”;
__toString());
http_response_code(500);
echo '系统忙,请稍后再试';
});
// 此时才引入框架/配置/自动加载
require_once 'vendor/autoload.php';
// ... 后续逻辑
注意:set_exception_handler() 只对未被捕获的 Throwable 生效;一旦某处写了 catch 却没重新抛出,这个处理器就收不到。
错误转异常要区分 error_reporting 级别
PHP 的 error_reporting 决定了哪些错误会被触发。直接用 set_error_handler() 把所有错误都转成异常,可能让 Notice 或 Deprecated 导致流程中断——这通常不是你想要的。
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
推荐做法是只转换实际会影响运行的级别:
- 在生产环境,建议只将
E_ERROR、E_PARSE、E_CORE_ERROR、E_COMPILE_ERROR、E_USER_ERROR转为异常 - 用
error_reporting() & $errno判断是否该处理,避免覆盖ini_set('display_errors', 'Off')的意图 - 不要在
error_handler中调用trigger_error(),否则可能递归触发自身
示例片段:
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
return false; // 让PHP按默认方式处理(如忽略)
}
if (in_array($errno, [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR])) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
});
日志记录必须包含上下文,不能只记异常消息
$e->getMessage() 往往只有“SQL error”,而真正需要的是“哪个用户、访问哪个URL、POST了什么数据、数据库连接参数是否正确”。没有上下文的日志等于没记。
记录时至少补全以下字段:
- 当前请求方法与完整URL(
$_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI']) - 用户标识(如
$_SESSION['user_id']或 token 解析结果,注意脱敏) - 请求体摘要(
substr(json_encode($_POST), 0, 200),防日志爆炸) -
$e->getTraceAsString()—— 不要用$e->getTrace()直接序列化,体积大且难读 - PHP版本、当前脚本路径、内存使用(
memory_get_usage())
线上务必关闭 display_errors,但确保 log_errors = On 且 error_log 指向可写文件或 syslog。
异常处理最易被忽略的一点:**异步任务(如 CLI 脚本、队列消费者)的异常不会经过 Web 入口的 set_exception_handler,必须单独配置**。










