PHP & Laravel 升版準備及流程分享

YUKI OTA
AsiaYo Engineering
Published in
12 min readAug 4, 2022

隨著公司業務規模不斷的成長,功能及商業需求不斷增加的同時,你手上的專案是否也有一段時間沒有做版本更新了呢?

從商業上的考量來說,版本更新是一件需要花費人力成本和時間才能進行,但無法讓產品有實質收益的作業。

但是當目前的系統版本、套件停止維護或更新、安全性上的考量、又或是在版本更新後能夠有更好的開發環境或執行效能,升級就變成一件有意義(能夠拿來說服老闆)的事情了XD

筆者是在 2022/2 月時加入 AsiaYo 的產品團隊,擔任 Backend Engineer 。
還記得剛進來的第一天 Mentor 及 Leader 交辦給我了兩件任務:

  1. 寫測試
  2. 將現有PHP 7.1專案的版本升級 7.3

於是筆者便透過寫測試暸解專案架構的同時,開始研究及嘗試如何幫現有的專案做版本升級。

這次AsiaYo將其中一個PHP 7.1 + Laravel 5.5的專案升級到了PHP 7.3 + Laravel 7。
從剛開始不斷的搜集、閱讀官方文件、尋找可用的工具,慢慢地建立了一個階段性將版本升級的流程。
在接下來的內容中將會把這次升版準備及過程,還有搭配到的小工具在這邊與大家分享。

版本升級準備:

我們在決定版本升級前,先整理了版本升級過程中需要的文件。

包括:

  1. PHP 官方升版文件
  2. Laravel 官方升版文件
  3. 過去其他專案環境升到相同版本號時的 changelog & PR
  4. packgist.org

我們從上述的文件中先分析了升級可能會需要更新到的程式碼、套件,最後決定在升級 PHP 7.3 的同時,也一併更新目前的 Laravel 版本。

會選定 PHP 7.3 & Laravel 7 的主要考量是版本的穩定性、以及該版號為目前大部分專案環境所使用的版本,我們想要讓所有專案開發體驗一致,進而提升開發效率,因此決定來進行這次的升版作業。

版本升級指引:

Laravel 升級

在開發時,我們選擇一次升級一個Laravel版號進行階段性升版。

(例如: 5.5 → 5.6 → 5.7 → 5.8 → 6.x → 7.x )

這樣做的好處是: 當升級一個版本遇到問題的時候,隨時可以從升級版本的官方文件中找到發現哪裡做了異動。

Laravel 官方升級文件

Laravel 官方升級文件已經把每個版本 PHP 最低版本需求、最基本的 Updating Dependencies 、每項修改對系統的影響層級(High, Medium, Low)、 閱讀文件所需的時間都寫得非常清楚。

(不過實際讀完做升版所花的時間每次都遠高於上面的預估時間)

在這邊筆者也將這次更新 Laravel 幾個較重大的異動做出整理,提供給大家參考。

Laravel 5.6 :

Laravel 5.8 :

Laravel 6.x :

Laravel 7.x :

更多升級相關的變更,可以參考官方文件

PHP 升級

PHP 升級的部分,我們以升級 7.2 為例,需要閱讀的主要是這三份文件:

我們會需要從 Backward incompatible changes 去檢查原來的函數在參數傳遞或回傳中做了什麼修正、還有從 Deprecated features 去查看專案中是否有用到這些方法及函數。
除了不相容的修正外也需要閱讀 New features 來了解這次升級中帶來了那些好用的新特性,可以在這次升級或日後專案開發中做使用。

筆者在這邊也整理了這次更新 PHP 7.2 & 7.3 中的一些新特性及修改提供大家參考。

PHP 7.2 :

  • 新的參數及回傳值類型宣告(object)
  • 允許重寫抽象方法 (Abstract method overriding)
  • 使用Argon2算法生成密碼
  • 參數類型推導
  • 允許分組命名空間的尾部逗號
  • count() 嚴謹化

PHP 7.2 棄用方法可以參考官方文件

PHP 7.3 :

  • Heredoc & Nowdoc 語法更靈活的縮排
  • 新增JSON_THROW_ON_ERROR參數來取得JSON錯誤
  • list () 賦值引用
  • is_countable() 函數 (因應PHP 7.2 count() 嚴謹化的修改)
  • array_key_first() & array_key_last()

PHP 7.3 棄用方法可以參考官方文件

雖然官方文件不能保證你升版絕對不會踩到坑,不過照著官方文件走過至少能夠確保升版異動的正確性。

“讀官方升版文件,確認專案中有沒有棄用的方法、異動的class或檔案”

這項作業是版本升級中最重要的一件事情!

套件相依性檢查

一邊讀文件,一邊把需要修改的程式碼都調整後,下一步就要來跑 composer 更新。
想當然的… 一定會有一連串套件相依問題噴出來

這個時候就需要透過 packgist.org 來檢查 composer 套件的相依性了。

以 sentry / sentry-laravel 這個套件為例:

從 requires 上可以得知,目前的版本 0.9.2 中 illuminate/support 相容的版號是 5.0.*|5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*
illuminate/support 是屬於 Laravel 框架本身內建的套件。(上面的版號與 Laravel version 相同)

如果我們今天要升級到 Laravel 5.7 ,那麼照 packgist.org 上所寫至少要升級到 0.10 才可以。

至於套件要升到哪個版本號,筆者的看法是考量有三點。

  1. 如果有其他相同執行環境使用此套件,版本號一致為原則。
  2. 若非 1 的情形,選擇能夠相容的最新版號,但如果那個版號是套件最新版本那就選前一個大版號,預防最新版本可能會有未知的 bug 發生。
  3. 如果發現 2 的版號對系統影響巨大,就考慮升級前版號最接近的版本。

但有時候升版會遇到套件之間的深深互相依賴真的會很頭痛。

php-cs-fixer & paratest

像是 php-cs-fixer & phpunit & paratest 三個套件只要更新了其中一個可能就會動到另外兩個,加上升級後測試、 linter 過不了就夠你崩潰一段時間了~

另外,套件升級也需要注意這次升級修改了哪些地方,有沒有在專案中使用到套件已經棄用的方法。

測試

成功將版號升上去,繼續跑測試來看結果。

可以看到有失敗的Test case出現,這個時候就只能一個一個釐清問題去解決了。

在版本升級與測試的過程難免會遇到測試結果失敗的情況,不過也因為過往的開發有補上測試,因此可以在升版過程中,大幅度降低升版的風險。

升級流程

總結來說,每做一次的版本升級都是按照以下流程進行:

“讀官方文件→檢查套件相依性→升級→檢查套件相依性→測試”

在幫專案升級時,也要注意你的 local 環境、線上環境和部署是否也要同步做更新。

像筆者在這次 PHP 升級過程中,因為 local 環境的設定忘了調整,導致多花了不少時間在找 bug…

升版時的輔助小工具:

PHPCompatibility:

這次使用了 PHPCompatibility 來掃描了專案是否有PHP新版本中已經棄用的方法存在。

在安裝需求上,只要你的專案是 PHP 5.4 版本以上,並且需要 PHP CodeSniffer2.6.0+ 就能夠使用此套件。

安裝流程可參考下面步驟或官方文件:

composer require –dev phpcompatibility/php-compatibility

安裝完成後,需要在 composer.json 中的 script 加上 phpcs 的 config setting:

“scripts”: {
“post-install-cmd”: “\”vendor/bin/phpcs\” — config-set installed_paths vendor/phpcompatibility/php-compatibility”,
“post-update-cmd” : “\”vendor/bin/phpcs\” — config-set installed_paths vendor/phpcompatibility/php-compatibility”
}

最後在跑 composer run 執行上面的 script 即可。

使用的話只需要執行下面的這段指令:

./vendor/bin/phpcs -p ./app/ ./tests/ ./config/ ./routes/ — standard=PHPCompatibility — runtime-set testVersion 7.3 — report-full=./update.log

簡單說明一下這段指令, PHPCompatibility 主要是會透過 phpcs 來掃描專案中指定的路徑(在這邊我們是設定 ./app/ ./tests/ ./config/ ./routes/ 這幾個資料夾),testVersion 這邊是設定你想要升級的PHP版本號(在這邊我們是設定 7.3 )。

最後會產出一份 ./update.log 的報表,會將掃描過專案後的 warning 及 error report 都放在這個 log 檔案內。

以我們這次試著掃瞄了升級的專案後,專案內的原始碼很幸運的並沒有棄用的方法存在,只有發現 namespace 的命名 warning 。

(不過也有用 phpcompatibility 掃描了 ./vendor 資料夾發現套件中有一些棄用的方法存在,所以也可以透過 phpcompatibility 掃描套件資料夾來評估要不要幫套件升級)

PHP Rector:

PHP Rector 是一個可以透過套用規則來自動化修改、重構及掃描程式碼的套件,在官方文件中目前已經有超過 500 種規則可以使用。

在這一次我們試著用 PHP Rector 中內建的幾個規則來協助檢查了專案中是否有需要修改的程式碼。

安裝流程可參考下面步驟或官方文件:

composer require rector/rector — dev

安裝完成後,需要建立一個初始化 config 腳本:

./vendor/bin/rector init

下面是筆者整理出來 config 的基本使用以及範例,提供給大家做參考。

使用時只要執行下面的這段指令即可:

./vendor/bin/rector process — dry-run

但需要注意的是它是重構工具,所以記得加上 dry-run ,否則不小心整個專案可能就被你重構完了XD

也因為它主要的用途還是在重構這件事情,所以在這次使用 Rector 都是作為升版檢查的參考使用~

上述的兩個套件筆者使用過的心得是可以作為升版時的輔助使用,但要完全靠套件來做升級並不靠譜。

另外, Laravel 9 的官方文件中也有推薦了一款(用錢可以解決的)自動化升版的工具 Laravel Shift ,只要綁定 github repo 後,就會自動化完成升版的修改及語法優化發到PR上。

除了付費功能,也有提供幾個免費工具,有興趣的話也可以試用看看:

Laravel Linter

PHPUnit Shift(PHP Unit 6, PHP Unit 8, PHP Unit 9)

Can I upgrade Laravel yet?

總結:

經過前面分享的升級流程後,筆者在這邊總結 PHP 、 Laravel 升版作業的幾個重點:

  • 參考過去其他專案升版時的 PR 跟 changelog ,升版後也要紀錄這次升版的 PR 跟 changelog 。
  • 搭配幾個輔助套件( phpcompatibility 、 rector )來進行升版作業
  • 讀官方升版文件,確認專案中有沒有棄用的方法、異動的 class 或檔案
  • 透過 packgist.org 來檢查套件版本的相依性
  • 一次升級一版會比較好掌握問題
  • 套件更新時肯定會遇到衝突,更新成功後也要檢查修改了什麼
  • 平時有寫測試的習慣,升版的時候會大大幫助你
  • 在 Docker 環境下進行更新作業才能在新舊版本之間來去自如

非常感謝大家的收看:)
這次也是筆者第一次進行版本更新的作業,如果有任何升版上的疑問或不清楚的地方,歡迎大家在下方留言。

.........

最後是文末跑馬燈!

AsiaYo 後端 Backend/前端 Frontend 工程師持續擴編招募中(CakeResume),我們的工程師文化是:

  • Technique enthusiasts 熱愛技術,精進自我
  • Play fun 運用所學做出又酷又好玩的東西
  • Problem solving 成為一個 problem solver
  • Team working 透過團隊集思廣益,選擇最好的開發語言及系統架構
  • Give it a try 擁抱改變,錯了就修正

期待你/妳的加入,跟我們一起做出很酷又好玩的東西!

--

--

YUKI OTA
AsiaYo Engineering

後端工程師、轉職仔 下輩子的願望是當個水豚