Yii2中如何自定义严重异常的处理逻辑?
Yii2中如何自定义严重异常的处理逻辑?
我完全理解你的困惑——Yii2自带的错误/异常视图区分确实容易让人混淆,而且默认配置下,一些严重的PHP错误(比如未定义属性、对象转数组这类)会绕过你自定义的site/error动作,直接用系统的exception.php显示,这确实很头疼。
为什么会出现这个情况?
核心原因有两个:
- Yii2的
errorHandler组件默认在YII_DEBUG=true时,会优先显示带调用栈的exception.php视图,不管你是否设置了errorAction; - 像
Undefined property这类错误属于PHP原生的Error(而非Exception),在PHP7+里它们实现了Throwable接口,但你的原代码只处理了特定的Exception子类,没有覆盖所有Throwable类型。
解决步骤:完全接管所有错误/异常处理
下面是一套完整的配置和代码改造方案,能让所有错误(包括严重的PHP原生错误)都走你自定义的处理逻辑:
1. 调整errorHandler组件配置
在你的应用配置文件(比如web.php)里,修改errorHandler的配置,强制关闭系统自带的异常显示,并确保所有错误都指向你的自定义动作:
return [ 'components' => [ 'errorHandler' => [ // 指向你的自定义错误处理动作 'errorAction' => 'site/error', // 强制关闭系统自带的异常视图(不管DEBUG模式) 'displayException' => false, // 捕获所有级别错误 'errorLevel' => E_ALL, // 如果需要在DEBUG模式下也隐藏调用栈(可选) 'showExceptionDetails' => false, ], ], ];
2. 完善SiteController的actionError方法
修改你的actionError,覆盖所有Throwable类型(包含Exception和PHP原生Error),同时完善日志记录和统一响应格式:
public function actionError() { $handler = Yii::$app->errorHandler; $exception = $handler->exception; // 用Yii日志组件记录详细错误信息(比error_log更灵活,可配置日志目标) Yii::error([ 'error_type' => get_class($exception), 'message' => $exception->getMessage(), 'status_code' => $exception instanceof \yii\web\HttpException ? $exception->statusCode : 500, 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'trace' => $exception->getTraceAsString(), ], 'custom_error_handler'); // 设置响应状态码 Yii::$app->response->statusCode = $exception instanceof \yii\web\HttpException ? $exception->statusCode : 500; // 准备统一的JSON响应数据 $data = new \stdClass(); $data->error = true; // 根据环境返回不同的错误信息(开发环境返回详细信息,生产环境返回通用提示) if (YII_DEBUG) { $data->message = $exception->getMessage(); $data->details = [ 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'trace' => $exception->getTraceAsString(), ]; } else { // 针对不同错误类型返回更友好的生产环境提示 if ($exception instanceof \yii\web\NotFoundHttpException) { $data->message = '请求的资源不存在'; } elseif ($exception instanceof \yii\web\UnauthorizedHttpException) { $data->message = '未授权访问'; } else { $data->message = '服务器内部错误'; } } // 强制设置响应格式为JSON,适配前端/移动端 Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; return $data; }
3. 额外注意:处理PHP致命错误
极少数情况下,PHP的致命错误(比如内存耗尽)可能无法被Yii的errorHandler捕获,这时可以在入口文件(web/index.php)的最顶部添加全局错误捕获:
// 在Yii初始化之前注册全局Throwable处理器 set_exception_handler(function (\Throwable $exception) { // 记录日志 error_log('Fatal error: ' . $exception->getMessage() . ' in ' . $exception->getFile() . ':' . $exception->getLine()); // 返回JSON响应 http_response_code(500); echo json_encode([ 'error' => true, 'message' => YII_DEBUG ? $exception->getMessage() : '服务器内部错误' ]); exit; }); // 然后继续原来的Yii初始化代码 require __DIR__ . '/../vendor/autoload.php'; require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; $config = require __DIR__ . '/../config/web.php'; (new yii\web\Application($config))->run();
这样改造后,所有错误都会走你的自定义逻辑:
- 不管是HTTP异常(401、404)还是PHP原生错误(未定义属性、对象转数组),都会被捕获;
- 错误信息会被详细记录,方便排查;
- 前端/移动端会收到统一格式的JSON响应,便于处理;
- 开发环境和生产环境的错误展示逻辑分离,兼顾调试和安全。
备注:内容来源于stack exchange,提问作者TomR
相关产品推荐
相关产品推荐

