
PHP 8 常見的相容性問題與棄用警告
PHP 8 對舊程式碼的影響
PHP 8 系列在錯誤處理與型別檢查上比 PHP 7 嚴格得多。過去只是警告的情況,很多在 PHP 8 變成致命錯誤。
這對維護多年的舊系統影響最大——程式一直正常運作,升級後卻出現大量錯誤。
以下整理最常遇到的幾類。
一、警告升級為錯誤
PHP 8.0 把許多原本的警告改為拋出錯誤。最常見的幾種:
- 存取不存在的陣列鍵——過去是通知,現在仍是警告但更明顯
- 對非陣列使用陣列語法——現在會拋出錯誤
- 除以零——現在拋出 DivisionByZeroError
- 參數數量或型別不符——內建函式現在會拋出 TypeError
典型的修法
// 舊寫法 $name = $data['name']; // 建議 $name = $data['name'] ?? '';
二、傳入 null 的棄用警告
PHP 8.1 起,對內建函式的非可為空參數傳入 null 會產生棄用通知。
這是舊系統升級後最常見的大量警告來源,因為過去這樣寫完全正常。
// 會產生棄用通知 $len = strlen($maybeNull); $trimmed = trim($maybeNull); $upper = strtoupper($maybeNull); // 建議 $len = strlen($maybeNull ?? ''); $trimmed = trim((string)($maybeNull ?? ''));
這類通知現在不會中斷程式,但在未來的版本可能變成錯誤。 建議逐步修正而不是忽略。
三、動態屬性的棄用
PHP 8.2 起,在未宣告的類別屬性上直接賦值會產生棄用通知。
class User {
public $name;
}
$u = new User();
$u->email = 'a@example.com'; // 未宣告,產生棄用通知
三種處理方式
// 方式一:明確宣告(建議)
class User {
public $name;
public $email;
}
// 方式二:加上屬性標註(過渡用)
#[\AllowDynamicProperties]
class User { }
// 方式三:實作魔術方法自行管理
舊框架與 CMS 大量使用動態屬性,升級到 8.2 時會產生非常多通知。若無法立即重構,可先用方式二過渡,但應排入改善計畫。
四、字串與數字的比較行為改變
PHP 8.0 調整了非嚴格比較的規則。字串與數字比較時,改為以字串方式比較(除非字串是數值形式)。
// PHP 7:true('foo' 被轉為 0)
// PHP 8:false
var_dump(0 == 'foo');
// 兩者皆為 true
var_dump('1' == '01');
這個變更通常讓行為更符合直覺,但依賴舊行為的程式可能出現邏輯錯誤——而且不會有錯誤訊息,只是結果不同。
建議在比較時使用嚴格比較:
if ($value === 'expected') { }
五、已移除的函式與擴充
各版本陸續移除了一些舊有的功能。常見的包含:
- 舊的 MySQL 擴充——早已移除,應改用 mysqli 或 PDO
- 魔術引號相關函式
- 部分字串與陣列函式的舊別名
- each()——已移除,改用 foreach
檢查方式
用靜態分析工具掃描,可以在不執行的情況下找出使用了已移除功能的位置。
六、建構子與方法簽章的檢查更嚴格
子類別覆寫父類別方法時,參數與回傳型別的相容性檢查變嚴格。不相容時會直接拋出致命錯誤。
這在繼承層級較深的舊框架中特別容易遇到。
七、字串內插與大括號語法
部分舊的字串內插寫法已被標記為棄用:
// 已棄用的寫法
echo "值是 ${var}";
// 建議
echo "值是 {$var}";
echo "值是 $var";
怎麼有系統地處理
一、先讓所有問題可見
在測試環境設定:
error_reporting = E_ALL display_errors = Off log_errors = On
然後完整走過所有功能,收集日誌。
二、分類處理
| 類型 | 優先度 | 處理 |
|---|---|---|
| Fatal error | 最高 | 必須修,否則功能壞掉 |
| Warning | 高 | 可能造成邏輯錯誤 |
| Deprecated | 中 | 下一版的致命錯誤,應排入計畫 |
| Notice | 低 | 逐步改善 |
三、從共用的程式碼開始改
同樣的問題可能散布在數十個檔案中。先找出共用的函式庫或基底類別,改一處可能解決很多地方。
四、不要在正式環境隱藏棄用通知了事
把 error_reporting 調低確實能讓日誌乾淨,但問題仍然存在,只是被藏起來了。
正式環境可以不記錄棄用通知以免日誌爆量,但測試環境必須看得到,並排入改善計畫。
老系統的現實建議
如果系統很舊、原始碼被大幅改過又沒有文件,升級的工時可能超過重建。
判斷的參考:
- 錯誤數量龐大且散布廣泛
- 使用了已無維護的框架或套件
- 沒有測試可以驗證修改是否正確
- 原始碼與官方版本差異太大,無法直接套用官方更新
這種情況下,在乾淨的環境重建,往往比持續修補更划算——見網站改版的流程。
本文的設定與語法以 PHP 8.x 為例,實際的參數、預設值與支援狀態可能因版本與發行版而異。各版本的支援時程請以 PHP 官方公告為準。套用前請先在測試環境驗證,並確實備份原設定檔。