「PHP 沒有套件管理機制,大家都直接 Copy & Paste。」--具備 10 年經驗的資深 PHP 工程師。
套件管理機制,往往是現代語言必備的一環。
Rust 在發佈後不久便出現了 cargo;Golang 在社群的推動下也曾經出現過 godep、vendor、glide 等工具,並且由官方於 1.11 後基於 vgo 推出 go module。
C/C++ 其實也有套件管理機制,但仍有很大一部份的開發者直接使用內建套件管理機制(如 apt、dnf)安裝外部函式庫(例如 libcurl)。
Composer 是 PHP 常用的套件管理機制,並在 PSR-4 Autoloader 制定之後迅速成為現代 PHP 的基石。
舉例來說,以往如果希望使用 PHPMailer 來用 PHP 寄信,我們可能要到它的 source forge 上找到指定的 PHP 版本後下載 ZIP 檔,並在專案中解壓縮後用 include
或 require
的方式使用它。
在 composer 出現之後,我們只需要 composer require phpmailer/phpmailer
後 require vendor/autoload.php
即可使用。如果使用多個函式庫也不用分別引入,autoload.php
會處理好所有的事情。
需要使用別人已經寫好的 package,直接使用 composer require
指令。
composer require phpmailer/phpmailer
執行時,它會自動去確認目前系統環境是否可使用這個套件(前提是套件作者有設定),或是有沒有與其它套件衝突。
安裝完成後,它會在當前資料夾下建立 composer.json
、composer.lock
及 vendor/
的資料夾。
在有需要使用該套件的檔案的開頭處,加入引入的機制
<?php
// 此處的 __DIR__ 請自行代換成專案根目錄位置
require __DIR__ . '/vendor/autoload.php';
// 因為 Autoloader 預設是依賴 namespace 進行套件查找
// 要記得引入正確的 namespace
use PHPMailer\PHPMailer\PHPMailer;
// 這邊就可以使用
$mailer = new PHPMailer(true);
建立自己的 package 之前,需要在專案根目錄做 init
composer init
此時,composer 會詢問一些問題:專案名稱、專案類型、作者、授權條款,並且詢問是否需要安裝既有的套件。
之後,在專案根目錄下建立一個資料夾 src/
(通常我習慣使用這個名稱,但實際上是沒有規定的),並且修改 composer.json
{
"name": "chivincent/test",
"authors": [
{
"name": "Vincent Chi",
"email": "song374561@chivincent.net"
}
],
"require": {},
"autoload": {
"psr-4": {
"Chivincent\\Test\\": "src/"
}
}
}
註:上述的
Chivincent\\Test\\
應該依照自己的 project name 做修改。
在 src/
中可以自由撰寫你的程式,唯一要注意的是它的 namespace 必須是 composer.json
內所定義的(目前是 Chivincent\Test
)
// File: src/Main.php
namespace Chivincent\Test\Main;
class Main
{
public function hello()
{
echo 'Hello World';
}
}
當函式庫製作完成後,將其上傳至任何可以公開存取的 Git/Svn/Hg 位址(通常會建議用 GitHub),並且於 Packagist 登記。
在 Packagist 上登記的套件就可以直接被 composer require
所使用。
在 composer require
時,可以加入 --prefer-dist
加速套件的安裝。
PSR-4 的基礎是由 Filesystem 構成,當建立符合 namespace 的新檔案時,會自動去引入它(每次請求都是直接存取 Filesystem),其優點是不需要每次新增/刪除檔案時都重新編輯索引。
這功能在穩定的環境中(例如 production)是不需要的,因為在那樣的環境中並不會一直新增/刪除檔案,所以可以利用 composer 內建的功能優化 autoloader。
啟用方法:
"optimize-autoloader": true
install
或 upldate
時使用 -o
或 --optimze-autoloader
dump-autoload
時使用 -o
或 --optimize
composer install -o
# composer install --optimize-autoloader
這會讓 autoload 中建立一個 Hashmap,當有 namespace 進入時會優先尋找是否存在該 Hashmap 中,如果沒有的話再去 Filesystem 中尋找。
啟用方法
"classmap-authoritative": true
install
、update
或 dump-autoload
時使用 -a
或 --classmap-authoritative
composer install -a
# composer install --class-authoritative
與基礎優化類似,它會先建立 Hashmap,但是如果不存在該 Hashmap 中的 class 就不會再去 Filesystem 中尋找。
註:如果有啟用進階優化,就不需要再啟動基礎優化。
註:依官方文件說明,進階優化其實有兩個方法,但另一個需要用到 ACPu,在 OPCache 盛行的今天很少人會另外再多裝 ACPu,所以就不提了。
這四個指令相當實用
顯示所有已安裝的 package。
用 -t
可以讓其變為樹狀結構,或是直接指名 package name 可以查閱指定的 package 資訊。
composer show
composer show -t
composer show "symfony/http-foundation"
顯示某個 package 為什麼會被安裝。
用 -t
顯示樹狀結構。
composer why "symfony/http-foundation"
composer why "symfony/http-foundation" -t
顯示希望使用的 package 與哪一個已安裝的相互衝突。
composer why-not "laravel/framework" 6.0
語意化版本中,假設存在 A.B.C
這樣的版號,A
稱為主版號(Major);B
稱為次版號(Minor);C
稱為修訂號(Patch)
composer update 只會升級次版號:如果目前 package 使用版本為 1.0.0
,在 2.0.0
、1.1.0
及 1.0.1
推出後,composer update 僅會升級到 1.1.0
。
利用 outdated
可以查閱目前使用的 package 與最新版差異,會被 composer update 升級的將以紅色表示,主版號升級的則以黃字表示。
這篇算是呼應了我第一天所寫的:Modern PHP 中應該於專案根目錄存在 composer.json,這是因為無論是利用別人寫的專案或是自己建立的專案,都應該依賴 composer 進行套件管理。