Yii 2 內建 yii\web\ErrorHandler 元件,統一接管 PHP 錯誤與未捕獲異常,支援開發/生產模式差異化顯示、自定義錯誤頁面、錯誤操作路由、JSON/API 錯誤格式化。本文系統拆解核心流程與配置實戰。
set_error_handler()、set_exception_handler() 指向 ErrorHandler。yii\web\ErrorEvent / yii\web\ExceptionEvent。application / exception.ClassName)。YII_DEBUG 與 YII_ENV 決定顯示策略:| 模式 | YII_DEBUG | 顯示內容 |
|---|---|---|
| 開發 | true | 完整堆疊追蹤、原始碼片段、變數值 |
| 生產 | false | 友好錯誤頁面,隱藏敏感信息 |
// config/web.php
return [
'components' => [
'errorHandler' => [
'class' => 'yii\web\ErrorHandler',
'maxSourceLines' => 20, // 異常頁顯示原始碼行數
'errorAction' => 'site/error', // 指定錯誤操作路由(推薦)
// 'errorView' => '@app/views/errorHandler/error.php', // 自定義錯誤視圖
// 'exceptionView' => '@app/views/errorHandler/exception.php', // 自定義異常視圖
],
],
];
namespace app\controllers;
use Yii;
use yii\web\Controller;
class SiteController extends Controller {
public function actions() {
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
];
}
}
public function actionError() {
$exception = Yii::$app->errorHandler->exception;
if ($exception !== null) {
return $this->render('error', ['exception' => $exception]);
}
}
<?php
use yii\helpers\Html;
/* @var $exception \yii\web\HttpException|Exception */
?>
<div class="error-page">
<h1><?= Html::encode($exception->getMessage()) ?></h1>
<p>錯誤代碼:<?= $exception->getCode() ?></p>
<p>狀態碼:<?= $exception->statusCode ?? 500 ?></p>
<a href="<?= Yii::$app->homeUrl ?>">返回首頁</a>
</div>
use yii\web\NotFoundHttpException;
use yii\web\ForbiddenHttpException;
use yii\web\BadRequestHttpException;
throw new NotFoundHttpException('頁面不存在'); // 404
throw new ForbiddenHttpException('權限不足'); // 403
throw new BadRequestHttpException('參數錯誤'); // 400
throw new \yii\web\ServerErrorHttpException('服務器錯誤'); // 500
ErrorHandler 會自動設置正確的 HTTP 狀態碼並渲染對應視圖。
use Yii;
use yii\base\ErrorException;
try {
10 / 0; // 觸發 E_WARNING
} catch (ErrorException $e) {
Yii::warning("Division by zero: " . $e->getMessage());
}
// 程式繼續執行...
非致命 PHP 錯誤(E_WARNING、E_NOTICE 等)自動轉為 ErrorException 可被 try-catch 捕獲。
根據 Response::format 自動格式化:
html:渲染視圖(上述流程)。json/xml:返回結構化數據。// JSON 格式錯誤響應範例
{
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}
// config/web.php
'components' => [
'response' => [
'class' => 'yii\web\Response',
'on beforeSend' => function ($event) {
$response = $event->sender;
if ($response->data !== null && !$response->isSuccessful) {
$response->data = [
'success' => false,
'error' => [
'code' => $response->statusCode,
'message' => $response->data['message'] ?? 'Internal Server Error',
'details' => $response->data,
],
];
$response->statusCode = 200; // 統一返回 200,前端靠 success 判斷
}
},
],
],
最終輸出:
{
"success": false,
"error": {
"code": 404,
"message": "The requested resource was not found.",
"details": { "name": "...", "message": "...", "code": 0, "status": 404 }
}
}
繼承 yii\base\UserException 的異常,**無論 YII_DEBUG 如何**,都不顯示堆疊追蹤,視為用戶操作錯誤而非程式 Bug。
class InsufficientBalanceException extends \yii\base\UserException {}
throw new InsufficientBalanceException('餘額不足'); // 生產環境也只顯示訊息