引言
現代開發,很多的功能不需要自己從零開始實現,因為早就有人實現了這些功能,我們只需要把別人寫好的程式碼拿過來,按照說明來使用就可以了。
相對於自家的程式碼,這些別人家的程式碼就是所謂的 依賴 或者第三方庫。
顯然,手動從別人那兒把程式碼拷貝過來是一件麻煩事兒,特別是依賴非常多的時候。而且,別人家的程式碼有可能進一步依賴更多人的程式碼,這樣,你就不僅要解決自己的依賴,你還要解決依賴的依賴!毫無疑問,這其中的工作量是巨大的,人們迫切需要一個能一鍵解決專案依賴(包括依賴的依賴)的工具,於是,依賴管理工具應運而生。
Composer 是 PHP 的一個依賴管理工具。有了它,你可以很方便地給專案新增和刪除依賴,並且在專案中引用這些依賴也變得非常簡單。
下文將帶你一步一步構建一個使用 Composer 來管理依賴的專案。
新建一個資料夾,充當一個專案的根目錄,然後進入。
$ mkdir demo
$ cd demo
配置檔案
在專案根目錄下建立檔案 composer.json
,這個檔案用於說明專案的依賴和其他的一些後設資料。
$ tree
.
└── composer.json
一個很重要的欄位是 require
,物件型別,其中列出了專案所需的依賴。
{
"require": {
"monolog/monolog": "1.0.*"
}
}
如你所見,require
下的每一個鍵值對都意味著一個依賴。鍵值對包含了依賴的 包名 和對應的 版本 兩部分資訊:鍵名就是包名,鍵值就是要使用的版本。包名由 作者名稱 和 專案名稱 兩部分構成,中間用一個斜槓 /
隔開。
前面的例子中,將 monolog/monolog
的版本指定為 1.0.*
版本號可以有以下幾種形式:
示例 | 說明 |
---|---|
1.0.2 |
確切的版本號。 |
>=1.0 >=1.0, <2.0 <=1.0|>=1.1 |
比較範圍。逗號 , 解釋為邏輯與;豎線 | 解釋為邏輯或。 |
1.0.* |
相當於 >=1.0.0, <=1.0.9 ,萬用字元 * 可以是 0-9 中的任一個數字。 |
1.0 - 2.0 |
相當於 >=1.0.0, <=2.0.0 |
~1.2.3 |
相當於 1.2.3 - 1.2.9 ,指定一個最小版本,允許最後一個數字增長。 |
^1.2.3 |
相當於 1.2.3 - 1.9.9 ,指定一個版本,允許向下相容的更新。 |
安裝依賴
執行 Composer 的 install
命令,配置檔案中宣告的依賴就會被安裝,所有的包會被儲存到 vendor
目錄下。
$ composer install
接前面的例子,可以在 vendor/monolog/monolog/
目錄中看到 monolog/monolog
的原始碼。
$ tree
.
├── composer.json
├── composer.lock
└── vendor
├── autoload.php
├── composer
└── monolog
└── monolog
Composer 為每個作者單獨建立一個目錄,在作者目錄下,又為作者的每個專案單獨建立一個目錄。
首次執行 install
命令,Composer 還會將安裝的依賴的確切版本號寫入檔案 composer.lock
。此後再執行 install
命令,Composer 都會優先安裝 composer.lock
檔案中記錄的版本。
日後,如果需要檢查和更新依賴,可以使用 composer update
命令。
使用依賴
如果 Composer 只是下載、儲存和更新包,那 Composer 就談不上有很大作用。
你可能已經注意到,Composer 生成了檔案 vendor/autoload.php
,你只需要簡單地 include
或 require
這個檔案,就可以直接使用這些包所提供的類。
建立檔案 public/index.php
和日誌檔案 storage/logs/app.log
,現在的目錄結構如下:
$ tree
.
├── composer.json
├── composer.lock
├── public
│ └── index.php
├── storage
│ └── logs
│ └── app.log
└── vendor
├── autoload.php
├── composer
└── monolog
在 public/index.php
中包含 vendor/autoload.php
,然後直接例項化 monolog/monolog
日誌庫的類,記錄一條日誌。
// public/index.php
require __DIR__ . '/../vendor/autoload.php';
$log = new Monolog\Logger('app');
$log->pushHandler(
new Monolog\Handler\StreamHandler(
__DIR__ . '/../storage/logs/app.log',
Monolog\Logger::WARNING
)
);
$log->addWarning('Foo');
執行 public/index.php
,可以看到日誌已經成功寫到日誌檔案。
$ php public/index.php
$ cat storage/logs/app.log
[2018-10-01 12:04:16] app.WARNING: Foo [] []
工作原理
Composer 是如何做到自動載入第三方類的呢?這要歸功於 PHP FIG 所制定的自動載入規範 PSR-4。Composer 提供的 vendor/autoload.php
檔案已經實現了這些規範,你所要做的就是了解這些規範以及在 Composer 中如何使用。
PSR-4 的核心思想就是將一個頂級名稱空間與某個目錄對應起來,使得該名稱空間下的每一個類都能與一個確切的檔案對應。
例如,對於 App\Http\Kernel
類,如果將頂級名稱空間 App\
對映為目錄 app/
,則檔案 app/Http/Kernel.php
中應該包含 App\Http\Kernel
類。
建立檔案 app/Http/Kernel.php
,在這個檔案中定義類 App\Http\Kernel
類。
$ tree
.
├── app
│ └── Http
│ └── Kernel.php
├── composer.json
├── composer.lock
├── public
├── storage
└── vendor
// app/Http/Kernel.php
namespace App\Http;
class Kernel
{
//
}
在檔案 composer.json
中的 autoload
欄位中新增欄位 psr-4
,在這個欄位中新增一個鍵值對,鍵值為 App\\
,鍵值為 app/
,這樣就把將頂級名稱空間 App\
對映為目錄 app/
。
{
"require": {
"monolog/monolog": "1.0.*"
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
- 名稱空間名稱的最後一級必須帶上反斜槓
\
- 目錄名後面必須帶上斜槓
/
在檔案 composer.json
中,反斜杆必須寫兩個,因為在 json 中反斜杆具有特殊含義,兩個反斜杆才表示反斜杆本身。
值得注意的是,宣告中的路徑 app/
是相對於檔案 composer.json
而言的。例如,在 monolog/monolog
日誌庫的 composer.json
檔案中,可以找到如下自動載入器的宣告。
{
"autoload": {
"psr-0": {"Monolog": "src/"}
}
}
這裡的 src/
對應的是 vendor/monolog/monolog
目錄下的 src
目錄。
改動 autoload
欄位之後,需要執行 dump-autoload
命令,讓 Composer 重新生成 vendor/autoload.php
檔案。
$ composer dump-autoload
Generating autoload files
此後就可以直接使用 App\Http\Kernel
類了。
// public/index.php
require __DIR__ . '/../vendor/autoload.php';
// $log = new Monolog\Logger('app');
// $log->pushHandler(
// new Monolog\Handler\StreamHandler(
// __DIR__ . '/../storage/logs/app.log',
// Monolog\Logger::WARNING
// )
// );
// $log->addWarning('Foo');
$kernel = new App\Http\Kernel();
在 autoload
欄位下,除了 psr-4
欄位,還可以有 psr-0
、classmap
、files
欄位,它們分別對應 PSR-0、類表、檔案清單自動載入方式。
開發時依賴
require
命令用於新增新的依賴。
$ composer require "summerblue/generator:~0.5" --dev
選項 --dev
表示這是一個開發時才會用到的依賴,它將出現在 composer.json
的 require-dev
欄位中。
{
"require-dev": {
"summerblue/generator": "~0.5"
}
}
帶 --no-dev
選項執行 install
命令,開發依賴就會被跳過。