iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Claude AI

用 AI Agent 重構一套無框架的 legacy PHP 系統系列 第 5

Day 05:PHP 版本相容性驗證——本機新版 PHP vs 正式環境舊版 PHP 的陷阱

  • 分享至 

  • xImage
  •  

前言:本機測試都綠燈了,還會有什麼問題?

「AI 在本機把測試都跑過一遍,全部綠燈,這樣總可以放心合併了吧?」

如果你也這樣想過,先別急著點頭。這套系統正式環境跑的是 PHP 7.4,但開發機、CI 機、甚至 AI agent 執行指令的環境,版本可能完全不一樣。「本機測試通過」跟「這段程式碼在正式環境是對的」,中間隔著一整層版本落差——而 AI 很容易把前者講成後者。

這正好呼應 Day 01 立下的主題句:AI 給出的「已確認」結論,永遠只在它實際查過的範圍內成立。今天要講的,是這句話在「PHP 版本」這個維度上最具體、也最容易被忽略的一種樣貌。

今日目標

  • 理解「本機驗證通過」為什麼可能只是假訊號,而不是真的驗證
  • 認識 composer.json 版本限制寬鬆時,不同 PHP binary 會解出不同套件大版本這件事
  • 看一個真實案例:兩個 AI agent 各自在本機得出同一個錯誤結論,一路寫進程式碼
  • 建立一套「本機驗證結果」該怎麼標注可信度的習慣

版本落差怎麼發生的:從 composer.json 的一行寬鬆限制說起

這套系統的 composer.json 裡,對某個第三方時間處理套件的版本限制寫得很寬鬆,同時允許兩個大版本。這種寫法在一般情況下沒問題——理論上兩個大版本的公開 API 應該相容。但問題出在:「公開 API 相容」不等於「行為完全一致」,尤其是牽涉到系統底層設定的地方。

實際發生的狀況是這樣:本機開發機的系統 PHP 是一個較新的版本,composer install 會解出這個套件的新大版本;而 CI 跑的是正式環境對齊的 PHP 7.4,同一份 composer.json 會解出舊大版本。兩個大版本剛好在「時區設定會不會被套件尊重」這件事上行為不同——新版一律回傳 UTC、忽略 date_default_timezone_set(),舊版則會照常尊重。

如果你的專案沒有明確鎖版本,這種落差不會在 composer.json 裡留下任何痕跡,只有在實際執行時才會冒出來。

一個真實案例:兩個 AI agent,同一個錯誤結論

有一次,我讓兩個獨立的 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 解出的套件大版本落差風險越高
  • 真實案例:兩個 AI agent 在本機各自得出同一個錯誤結論,因為驗證環境本身就有偏差
  • 除了套件行為落差,也要注意語法層級的相容性——新版 PHP 語法在舊版正式環境直接 parse error
  • 具體做法:驗證結論要標注「用什麼版本驗證的」,牽涉套件行為的斷言要寫成自動化測試,不能只靠一次手動執行

明日預告

明天要接續這個主題往前一步:當你真的有了乾淨的基準版本,該怎麼把「這次改動真的引入的迴歸」跟「單純是本機環境雜訊造成的假紅字」分開——這是讓驗證結果真正可信的下一道關卡。


上一篇
Day 04:建立重構的「基準線」——分支策略與覆蓋率門檻
系列文
用 AI Agent 重構一套無框架的 legacy PHP 系統5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言