錯誤級別常量速查
| 常量 | 值 | 含義 | 建議 |
E_ERROR | 1 | 致命運行錯誤 (腳本終止) | 必須顯示 |
E_WARNING | 2 | 運行警告 (腳本繼續) | 必須顯示 |
E_PARSE | 4 | 編譯時語法解析錯誤 | 必須顯示 |
E_NOTICE | 8 | 運行時通知 (如未定義變量) | 開發顯示,生產隱藏 |
E_STRICT | 2048 | 代碼標準化建議 (PHP 5.4+ 併入 E_ALL) | 開發顯示 |
E_DEPRECATED | 8192 | 棄用功能警告 | 開發顯示 |
E_ALL | 32767 | 所有錯誤 (PHP 8.1+ 含 E_DEPRECATED) | 開發環境 |
正確關閉 Notice 的三種方式
1. 運行時動態設置 (單腳本/入口文件)
<?php
// 入口文件最開頭 (輸出前)
// 方式 A: 位運算排除 (推薦,清晰語義)
error_reporting(E_ALL & ~E_NOTICE); // 顯示除 Notice 外所有
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT); // 更精確
// 方式 B: XOR 切換 (舊寫法,易誤解)
error_reporting(E_ALL ^ E_NOTICE); // 等效於上面,但語義為「翻轉位」
// 方式 C: 只顯示嚴重錯誤
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// 完全關閉 (極不推薦,除非極特殊場景)
error_reporting(0);
2. php.ini 全局配置 (生產環境標準)
; php.ini
; 開發環境
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
error_log = /var/log/php_errors.log
; 生產環境 (推薦)
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE
display_errors = Off ; 絕不直接輸出到瀏覽器
display_startup_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
; 關鍵: 生產環境通過日志系統 (ELK/Sentry) 監控錯誤
3. Nginx/Apache 虛擬主機級別覆蓋
# Nginx fastcgi_param
fastcgi_param PHP_VALUE "error_reporting=E_ALL & ~E_NOTICE";
# Apache .htaccess / httpd.conf
php_value error_reporting 32759 ; E_ALL & ~E_NOTICE (32767-8)
關閉 Notice 的性能陷阱與真相
誤區: 「關閉 Notice 顯示就能提升性能」。
真相: error_reporting 只控制顯示/記錄,不影響 PHP 內核執行邏輯。未定義變量訪問、數組鍵不存在等操作,PHP 內核依然會執行完整的錯誤處理流程 (生成錯誤信息、調用錯誤處理器、檢查級別、決定是否輸出)。
結論: 代碼中大量 Notice 級錯誤依然會消耗 CPU/內存,唯有修復代碼 (定義變量、isset() 判斷、?? 空合併運算符) 才能真正提升性能。
修復 Notice 的現代化最佳實踐 (PHP 7/8)
1. 空合併運算符 ?? (替代 isset/empty)
// 舊寫法
$name = isset($_GET['name']) ? $_GET['name'] : 'default';
$config = isset($arr['key']) ? $arr['key'] : [];
// 新寫法 (PHP 7+)
$name = $_GET['name'] ?? 'default';
$config = $arr['key'] ?? [];
// 鏈式調用
$city = $user->profile->address->city ?? '未知'; // 需 PHP 8?-> 操作符
// PHP 8 安全鏈式
$city = $user?->profile?->address?->city ?? '未知';
2. 變量初始化習慣
// 循環前初始化
$sum = 0;
$list = [];
$html = '';
foreach ($items as $item) {
$sum += $item->price;
$list[] = $item->name;
$html .= "$item->name";
}
3. 數組鍵存在性檢查
// 檢查鍵存在 (含 null 值)
if (array_key_exists('key', $arr)) { ... }
// 獲取並刪除 (PHP 7+)
$value = $arr['key'] ?? null;
unset($arr['key']);
// 批量提取並設置默認值
['name' => $name, 'age' => $age] = array_merge(['name' => '', 'age' => 0], $input);
4. 嚴格模式與類型聲明 (PHP 7+)
declare(strict_types=1);
function process(array $data): void {
// 參數必須是數組,否則拋 TypeError (非 Notice)
$name = $data['name'] ?? ''; // 仍需處理鍵不存在
}
開發/生產環境差異化配置策略
<?php
// config/error.php
return [
'development' => [
'error_reporting' => E_ALL,
'display_errors' => true,
'log_errors' => true,
],
'production' => [
'error_reporting' => E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT,
'display_errors' => false,
'log_errors' => true,
'error_log' => '/var/log/php/app_errors.log',
],
];
// bootstrap.php
$env = $_ENV['APP_ENV'] ?? 'production';
$config = require "config/error.php"[$env];
ini_set('error_reporting', $config['error_reporting']);
ini_set('display_errors', $config['display_errors'] ? '1' : '0');
ini_set('log_errors', $config['log_errors'] ? '1' : '0');
if (!empty($config['error_log'])) ini_set('error_log', $config['error_log']);
// 自定義錯誤處理器 (生產環境接入 Sentry/日志系統)
if ($env === 'production') {
set_error_handler(function($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) return false; // 級別過濾
// 發送到 Sentry / 寫入結構化日志
error_log(json_encode([
'time' => date('c'),
'severity' => $severity,
'message' => $message,
'file' => $file,
'line' => $line,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5),
]));
return true; // 阻止默認處理器
});
}
總結清單
- 開發環境:
E_ALL + display_errors=On,盡早發現所有問題。
- 生產環境:
E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT + display_errors=Off + log_errors=On。
- 代碼層面: 使用
??、?->、初始化變量、array_key_exists 徹底消除 Notice 產生源,而非掩蓋。
- 監控: 生產錯誤日志必須接入告警系統 (Sentry, Promtail+Loki, ELK),Notice 級單獨統計趨勢,作為代碼質量指標。
- 嚴禁: 使用
@ 抑制錯誤 (極大性能損耗 + 隱藏真實 Bug),使用 error_reporting(0) 掩蓋所有錯誤。