4 月 132021
 

Source: 成為 Modern PHPer系列 第 11 篇 / 使用 composer

前言

套件管理機制,往往是現代語言必備的一環。

Rust 在發佈後不久便出現了 cargo;Golang 在社群的推動下也曾經出現過 godep、vendor、glide 等工具,並且由官方於 1.11 後基於 vgo 推出 go module。

C/C++ 其實也有套件管理機制,但仍有很大一部份的開發者直接使用內建套件管理機制(如 apt、dnf)安裝外部函式庫(例如 libcurl)。

Composer

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

需要使用別人已經寫好的 package,直接使用 composer require 指令。

composer require phpmailer/phpmailer

執行時,它會自動去確認目前系統環境是否可使用這個套件(前提是套件作者有設定),或是有沒有與其它套件衝突。

安裝完成後,它會在當前資料夾下建立 composer.jsoncomposer.lock 及 vendor/ 的資料夾。

  • composer.json 及 composer.lock 要加入版本控制
  • vendor/ 資料夾不要加入版本控制

在有需要使用該套件的檔案的開頭處,加入引入的機制

<?php

// 此處的 __DIR__ 請自行代換成專案根目錄位置
require __DIR__ . '/vendor/autoload.php';

// 因為 Autoloader 預設是依賴 namespace 進行套件查找
// 要記得引入正確的 namespace
use PHPMailer\PHPMailer\PHPMailer;

// 這邊就可以使用
$mailer = new PHPMailer(true);

建立自己的 package

建立自己的 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 的小技巧

加速套件安裝

在 composer require 時,可以加入 --prefer-dist 加速套件的安裝。

增加 autoload 效率

PSR-4 的基礎是由 Filesystem 構成,當建立符合 namespace 的新檔案時,會自動去引入它(每次請求都是直接存取 Filesystem),其優點是不需要每次新增/刪除檔案時都重新編輯索引。

這功能在穩定的環境中(例如 production)是不需要的,因為在那樣的環境中並不會一直新增/刪除檔案,所以可以利用 composer 內建的功能優化 autoloader。

基礎優化

啟用方法:

  • composer.json 中的 config 設定 "optimize-autoloader": true
  • 在 install 或 upldate 時使用 -o 或 --optimze-autoloader
  • 在 dump-autoload 時使用 -o 或 --optimize
composer install -o
# composer install --optimize-autoloader

這會讓 autoload 中建立一個 Hashmap,當有 namespace 進入時會優先尋找是否存在該 Hashmap 中,如果沒有的話再去 Filesystem 中尋找。

進階優化

啟用方法

  • 在 composer.json 中的 config 設定 "classmap-authoritative": true
  • 在 installupdate 或 dump-autoload 時使用 -a 或 --classmap-authoritative
composer install -a
# composer install --class-authoritative

與基礎優化類似,它會先建立 Hashmap,但是如果不存在該 Hashmap 中的 class 就不會再去 Filesystem 中尋找。

註:如果有啟用進階優化,就不需要再啟動基礎優化。
註:依官方文件說明,進階優化其實有兩個方法,但另一個需要用到 ACPu,在 OPCache 盛行的今天很少人會另外再多裝 ACPu,所以就不提了。

show, why, why-not, outdated

這四個指令相當實用

show

顯示所有已安裝的 package。

用 -t 可以讓其變為樹狀結構,或是直接指名 package name 可以查閱指定的 package 資訊。

composer show
composer show -t
composer show "symfony/http-foundation"

why

顯示某個 package 為什麼會被安裝。

用 -t 顯示樹狀結構。

composer why "symfony/http-foundation"
composer why "symfony/http-foundation" -t

why-not

顯示希望使用的 package 與哪一個已安裝的相互衝突。

composer why-not "laravel/framework" 6.0

outdated

語意化版本中,假設存在 A.B.C 這樣的版號,A 稱為主版號(Major);B 稱為次版號(Minor);C 稱為修訂號(Patch)

composer update 只會升級次版號:如果目前 package 使用版本為 1.0.0,在 2.0.01.1.0 及 1.0.1 推出後,composer update 僅會升級到 1.1.0

利用 outdated 可以查閱目前使用的 package 與最新版差異,會被 composer update 升級的將以紅色表示,主版號升級的則以黃字表示。

後記

這篇算是呼應了我第一天所寫的:Modern PHP 中應該於專案根目錄存在 composer.json,這是因為無論是利用別人寫的專案或是自己建立的專案,都應該依賴 composer 進行套件管理。

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

CAPTCHA Image
Play CAPTCHA Audio
Reload Image