パッケージ管理ツール「Composer」
今日では、多くのプログラミング言語において、開発プロジェクトにパッケージ管理ツールが欠かせないものとなりました。
既存資産の活用で「車輪の再発明」を避け、開発の効率化を助けてくれます。また、セキュリティ意識が高まる中で、厳密なバージョン管理や確実なアップデートも強く求められています。使いやすいパッケージ管理ツールがなければ、いずれも頭の痛い問題になるのではないでしょうか。
言語によってはパッケージ管理ツールを標準で提供されているものもある一方で、コミュニティ主導で3rdパーティツールとして提供されているものも多く存在しています。
PHPでは、Composerがデファクトスタンダードなツールです。コミュニティ主導で開発されているものですが、PHPを利用するプロジェクトであれば、Composerの利用は不可欠になっているといえそうです。
では、Composerはどのようにしてパッケージの存在を確認し、バージョンを解決するのでしょうか? そんな疑問に答えるべく、一連の流れを追ってみようというのが本稿の主旨です。
なお、内容はすべて執筆時点の最新版であるv2.8.2
を前提としています。
composer.jsonとcomposer.lock
多くの類似ツールと同様に、Composerでも「構成管理ファイル」「ロックファイル」によって依存パッケージを管理しています。
前者にあたるのがcomposer.json
で、後者がcomposer.lock
というファイルです。それぞれの役割は次のとおりです。
-
composer.json:プロジェクトが直接依存するパッケージ名と、許容するバージョンの範囲を指定。アプリケーション(プロジェクト)の開発者が設定するもの。パッケージの追加コマンド(
composer require
)によって更新される -
composer.lock:プロジェクトが間接的に依存するものも含めて、パッケージ名と詳細なバージョンを指定。Composerによって自動的に生成されるもの。追加済パッケージのバージョンアップ(
composer update
)によって更新される
例えば、composer require "hoge/fuga:^1.0.0"
と指定したら、パッケージhoge/fuga
のバージョン1.x系統の最新版(例えば1.27.5
)が利用されます。その際には、composer.json
にはhoge/fuga:^1.0.0
が、composer.lock
にはhoge/fuga:1.27.5
が記述されます。
この例は、「自身が依存を持たない単一のパッケージの取得」という極めて単純なシナリオになっています。それでも、分解して捉えると複数の仕事が含まれていることに気付きます。
-
パッケージ
hoge/fuga
が存在するか・利用可能かのチェック -
hoge/fuga
の利用可能なバージョンのチェック -
バージョン解決の戦略[1]に基づいて
^1.0.0
の条件に合致するバージョンの特定
[1] デフォルトでは、安定版かつ最新版を取得します
これに加えて、一般的なComposerの利用場面では、「間接依存を持つ場合」「複数パッケージ同士が同じパッケージに依存する場合」「インストールの前提条件が指定されている場合(PHPのバージョンや拡張の有無など)」等の更に複雑な要件が発生します。
こうした問題は、どのように解決されているのでしょうか? 具体的な仕組みを見ていきましょう。