「AI 在本機把測試都跑過一遍,全部綠燈,這樣總可以放心合併了吧?」
如果你也這樣想過,先別急著點頭。這套系統正式環境跑的是 PHP 7.4,但開發機、CI 機、甚至 AI agent 執行指令的環境,版本可能完全不一樣。「本機測試通過」跟「這段程式碼在正式環境是對的」,中間隔著一整層版本落差——而 AI 很容易把前者講成後者。
這正好呼應 Day 01 立下的主題句:AI 給出的「已確認」結論,永遠只在它實際查過的範圍內成立。今天要講的,是這句話在「PHP 版本」這個維度上最具體、也最容易被忽略的一種樣貌。
composer.json 版本限制寬鬆時,不同 PHP binary 會解出不同套件大版本這件事這套系統的 composer.json 裡,對某個第三方時間處理套件的版本限制寫得很寬鬆,同時允許兩個大版本。這種寫法在一般情況下沒問題——理論上兩個大版本的公開 API 應該相容。但問題出在:「公開 API 相容」不等於「行為完全一致」,尤其是牽涉到系統底層設定的地方。
實際發生的狀況是這樣:本機開發機的系統 PHP 是一個較新的版本,composer install 會解出這個套件的新大版本;而 CI 跑的是正式環境對齊的 PHP 7.4,同一份 composer.json 會解出舊大版本。兩個大版本剛好在「時區設定會不會被套件尊重」這件事上行為不同——新版一律回傳 UTC、忽略 date_default_timezone_set(),舊版則會照常尊重。
如果你的專案沒有明確鎖版本,這種落差不會在 composer.json 裡留下任何痕跡,只有在實際執行時才會冒出來。
有一次,我讓兩個獨立的 AI agent 分頭處理跟時間處理相關的兩個任務。兩個 agent 各自在本機環境跑了驗證,各自都觀察到「這個套件好像忽略了時區設定」,並且各自基於這個觀察寫了對應的處理邏輯——用手動轉換時區的方式繞過套件本身的行為。
兩個 agent 互不知道對方的存在,卻得出了完全一樣的錯誤結論。這不是巧合,而是因為他們觀察到的現象本身就是真的——只是那個現象只在本機這個特定版本的環境下才成立。PR 送上 CI 之後,兩支都紅了:CI 上的舊版套件本來就會尊重時區設定,AI 加上去的「修正」反而讓時區被轉換了兩次。
用一組對照來看這件事:
❌ 沒有標注驗證邊界的版本:
AI:「已在本機驗證,這個套件忽略時區設定,
已加上手動轉換邏輯修正這個問題。」
→ 「已驗證」聽起來是個確定的事實,但驗證環境跟正式環境的套件大版本不同
✅ 標注驗證邊界的版本:
AI:「在本機(PHP 新版本,套件解出 X.x)觀察到套件忽略時區設定;
尚未在 CI 對齊的 PHP 7.4 環境(套件解出 Y.x)驗證同一行為,
這兩個大版本在時區處理上可能不一致,建議先確認 CI 環境的實際版本再下結論。」
→ 誠實區分「我在哪個環境觀察到什麼」和「這個結論適用的範圍」
AI 在本機得出的觀察,可能只反映本機環境,不是放諸四海皆準的真相——這句話值得貼在每一次「本機驗證通過」的旁邊。
版本落差不只發生在第三方套件的行為上,也發生在你自己寫的程式碼語法上。如果開發機的 PHP 版本比正式環境新,很容易在不知不覺間寫出正式環境根本跑不起來的語法——union return type、mixed 型別、建構子屬性提升是 PHP 8.0 才加入的語法,trait 常數則要到 PHP 8.2 才支援,這些寫法在 PHP 7.4 都會直接 parse error。
這類問題比套件行為落差更好抓,因為它是語法層級的錯誤,理論上可以用 lint 工具在合併前攔下來。但如果流程裡沒有明確要求「用正式環境對齊的 PHP 版本跑一次 lint」,AI 寫出來的程式碼在本機(新版 PHP)完全正常執行、语法檢查也過,直到部署那一刻才爆炸。
這個案例後來變成一條具體規則:任何「已在本機驗證」的結論,都要附帶「用什麼 PHP 版本驗證的」這個資訊;牽涉到第三方套件行為的部分,還要額外附上「這個套件在這個版本解出的大版本是什麼」。這聽起來是個小小的紀律,但它把一句模糊的「已驗證沒問題」,變成一句可以被追問、可以被複查的具體宣稱。
同時,凡是牽涉到時區、日期這類套件層級行為判斷的斷言,不能只靠一次手動執行(例如在 shell 裡跑一行程式碼看輸出)就當作結論,要求寫成明確斷言值的自動化測試——這樣才能在版本組合改變時,讓測試本身告訴你「假設不成立了」,而不是等到正式環境出事才發現。
今天講的具體症狀(composer.json 寬鬆版本限制、PHP 8 語法糖)是 PHP 生態特有的,但**「本機工具鏈版本跟正式環境不一致,會讓驗證結果變成假訊號」這件事在任何語言都會發生**——Node.js 專案裡 package.json 沒鎖死版本、本機 Node 版本比 CI 新;Python 專案本機用新版直譯器、正式環境還在舊版;Java 專案本機 JDK 版本比部署環境新,都是同一種風險的不同外殼。真正要記住的不是「PHP 7.4 有陷阱」,而是「任何沒有明確鎖版本的工具鏈,本機驗證都可能只是假訊號」。
回想你最近一次接受 AI「已在本機驗證」的結論時,你知道那個驗證是在哪個 PHP 版本、哪個套件版本下跑的嗎?如果答案是「不知道」,那個結論的可信度,其實跟你自己都說不清楚。
composer.json 版本限制寫得越寬鬆,不同 PHP binary 解出的套件大版本落差風險越高明天要接續這個主題往前一步:當你真的有了乾淨的基準版本,該怎麼把「這次改動真的引入的迴歸」跟「單純是本機環境雜訊造成的假紅字」分開——這是讓驗證結果真正可信的下一道關卡。