モダンなPHPの依存管理(パッケージ管理)に既に欠かせないものとなったComposerの導入と運用方法について説明します。「仕事で使えるComposer」でもざっくりと紹介しましたが、今回はもうちょっとだけ詳細に書きます。
概要についてざっくりと知りたい型は、先にこちらのスライドをご覧ください。
Composerとは何か
ComposerはPHPのパッケージ(ライブラリやツールなど)をインストールするためのツールです。英語ではComposer is a dependency manager.
と説明されます。
ほかのプログラミング言語のエコシステムとして、Rubyでのgem
コマンドとBundlerを組み合せたもの、Node.jsのnpmに相当します。Composerはこの二つと比べても後発だけあって、それらの良いところが取り入れられたものです。
Packagist
Packagist (The PHP Package Repository)はComposerデフォルトのリポジトリです。Rubyのrubygems.org、PythonのPyPI(Python Package Index)、Node.jsのNPM(npmjs.com)に相当します。
各言語のパッケージマネージャーの動向を定点観測するModule Countsでは先述の各言語のパッケージ数が集計されて居ります。パッケージ数の増加と言語エコシステムの充実には直接の関係はありませんが、PHPにおいてもRubyやPythonに負けない規模の活発な開発コミュニティが育ってることは確かです。
Composerでできること
- 依存パッケージ(PHPライブラリ)を管理する
- インストール
- 更新状態の確認
- ライセンスの一覧
- PHPプロジェクトの依存関係を定義する
- PHPのバージョンとか
- 必須のPHP拡張とか
- コマンドラインツールをインストールする
- クラスの自動ロード(オートローディング)を簡単にする
Composerが可能にすること
従来のPHPではrequire_once("Auth/Auth.php");
のようにパッケージに含まれる個別のファイル名を名指しで読む方式でした。
Composerはライブラリを含めた依存性をまとめてインストールしてくれるだけではなく、PHPが本来持つクラスのオートローディングの仕組みを使って、自前のコードとライブラリのコードを自然に統合してくれることにあります。
どのような原理で動作するのかの説明についてはincludeって書きたくない僕たちのためのオートローディングとComposerに書きました。
PEAR
Composerの前の世代のPHPにおけるパッケージ管理ツールはPEARでした。PEARとは何かについてはManual :: What is PEAR?に説明されます。現在のPHPコミュニティにおいては既にあまり重要視されて居りません。
PEARの公式channelは後方互換性を極力維持する方針でしたが、PHP4の時代からあるためE_STRICT
レベルのエラーが大量に発生する。PHPには5.3で名前空間(namespace)の機構が取り入れられましたが、
PEARからComposerへの時代に以降した象徴的なできごとは、2014年のPHPUnitのPEARによる提供の終了でした。PHPUnitは2014年4月21日にリリースされた3.7.35および4.0.17をもってPEARを対象とした最終リリースとし、年末をもって専用のPEARチャンネル(pear.phpunit.de
)をシャットダウンしました(End of Life for PEAR Installation Method · sebastianbergmann/phpunit Wiki)。
用語の整理
パッケージ (package)
公式のドキュメントでは「何かを含むディレクトリ」A package is essentially just a directory containing something.
と説明されます。ComposerはPHPのために設計された依存性マネージャーなので、典型的にはPHPのコードやそれに付随するデータが含まれます。
パッケージは必ず、vendor/name
形式の「名前」と「バージョン」を持ちます。私(zonuexe
)が作ったマストドンAPIクライアントのパッケージ名は、典型的にはzonuexe/mastodon-api
のようなパッケージ名になります。
ライブラリとしてリポジトリに公開するものだけでなく、Composerで管理されるものはパッケージと呼ばれます。パッケージのタイプにはlibrary
とproject
がありますが、基本的にはデフォルト(library
)で困らないです。
バージョン (version)
バージョンは、よく知られたソフトウェアの更新状況を示す1.2.4
や0.1.12
のような数字による表記です。小数点数ではなく、単に.
で区切られた数字(あるいは、そのほかの文字)の羅列です。
有名なバージョン付けのガイドラインとしてはセマンティック・バージョニング(semver)があり、このルールにおいては先頭から順に major.minor.patch
と呼ばれます。また、正式リリース前のバージョンには1.2.3-pre
, 1.2.3-alpha
, 1.2.3-beta
, 1.2.3-rc.1
, 1.2.3-rc.2
のような識別子をつけることができます。(ただし、これはバージョンの大小関係においては単純にアルファベットの辞書順に解決されることには注意が必要です)
リポジトリ (repository)
Composerがパッケージを検索するサイトのことです。デフォルトではPackagistが登録され、ここからダウンロードすることができます。
Composer実行ファイルを取得する
Composerは一般的にはコマンドラインのコマンドから利用されます。配布されるファイルの実体としてはPhar形式ですが、利用者はそこまで気にする必要はありません。
Windowsにコマンドをインストールする
別途PHPのインストールは必要ですが、Windows環境でもComposerは動作します。
Composerインストール手順(Windows)を参照してください。
composerコマンドとしてインストールする
はじめにDownload Composerの説明通りに実行します。が、ここまでやってもcomposer
をコマンドとしてインストールはされず、 現在のディレクトリにcomposer.phar
が置かれるだけ です。
一般的なコマンドラインシェルからは、PATH
といふ環境変数に含まれるディレクトリに存在するファイルを実行することができます。環境変数はコマンドラインで echo $PATH | tr ":" "\n"
でチェックできます。
% echo $PATH | tr ":" "\n"
/usr/local/sbin
/usr/local/bin
/usr/bin
/usr/local/opt/coreutils/libexec/gnubin
/bin
/usr/sbin
/sbin
つまり、新しいコマンドとしてcomposer
を登録するには「A: ファイルを置いたディレクトリをPATH
に追加する」「B: PATH
に含まれるディレクトリにファイルを置く」のどちらかを決めなければいけません。
A: ファイルを置いたディレクトリをPATH
に追加する
ユーザーの実行権限で作成できるディレクトリを一つ決めて、そこに実行ファイルを設置する方法です。筆者は $HOME/local/bin
ディレクトリを利用するのが好みです。ほかの実行ファイル置き場を決めてある場合は、改めて作業する必要はありません。
% mkdir -p $HOME/local/bin
% chmod 755 composer.phar
% sudo mv composer.phar /usr/local/bin/composer
# Z Shellの場合
% echo 'PATH=$HOME/local/bin:$PATH' >> ~/.zshrc
# GNU Bashの場合
% echo 'PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
コマンドを実行するためにPATH
環境変数にディレクトリを追加することを、俗に「PATH
を通す」と呼びます。
B: PATH
に含まれるディレクトリにファイルを置く
一般的なUNIXシステムでは、管理者が手動で追加するコマンドは /usr/local/bin
に配置される慣習があります。ただし、このディレクトリを操作するにはコンピュータの管理者権限(root
ユーザー、あるいはsudo
コマンドの実行権限)が必要です。
% chmod 755 composer.phar
% sudo mv composer.phar /usr/local/bin/composer
C: .phar
として利用する
上記のようにコマンドとしてインストールせずとも、php
コマンドを介してComposerを起動することができます。デメリットは、composer.phar
ファイルがどこにあるのか気を配らなければいけないことです。裏返せば、上記のようにコマンドとしてインストールするメリットとは「作業中にcomposer.phar
がどこにあるのかに気を配らなくても良くなる」ことです。
さて、composer
をコマンドとしてインストールしない場合、php composer.phar
として実行することができます。
# 現在のディレクトリに composer.phar が存在する場合
% php ./composer.phar
# ホームディレクトリに composer.phar が存在する場合
% php ~/composer.phar
# どこか別の場所 /path/to に composer.phar が存在する場合
% php /path/to/composer.phar
Composerのユースケースを想定したとき、一部の運用者しか直接composer
コマンドを利用しない場合は、この方法で十分なことがあります。
実際に筆者が業務で開発するプロジェクトにおいてもこのような運用です。ほとんどの作業者はComposerの存在を意識しなくても、全体のセットアップスクリプト内に含まれるからです。
D: .phar
として利用するラッパーを書く
初カキコ…ども… 俺みたいなAndroidでPHP動かしてる腐れぞぬ野郎、他に、居ますかって居ねーか、はは
残念ながら、上記の「A」「B」どちらの方法でもcomposer
をコマンドとして利用できない環境も実際存在します。(具体的には/usr/bin/env
が存在しないAndroidなどが該当します)
AndroidのTermuxでPHP+Composerを動かしたい、みたいなひとはラッパースクリプトを書けばいけます。
#!/data/data/com.turmux/files/usr/bin/bash
php $HOME/local/bin/composer.phar "$@"
↑ <details>
の中は読まなくてもいいです。
Composerを更新する
Composerは不定期に更新されるので、composer self-update
コマンドで更新されます。
% php composer.phar self-update
Updating to version 1.4.1 (stable channel).
Downloading (100%)
Use composer self-update --rollback to return to version 1.4.0
特に1.3.0
で大きな最適化が入ってますし、バージョンを上げない理由は特にないです。
Composerを高速化する
Composerはパッケージを検索・取得する際にPackagistやGitHubなど大陸をまたいで直列で通信しまくる仕様のため、巨大なパッケージをダウンロードする際は氏ぬほど待たされることがあります(詳しくは @Hiraku の光遅い問題を克服してcomposerを10倍速くした話 - Mercari Engineering Blogを読んでください)。
さて、そのblog記事の通りpackagist.jpと並列ダウンロードプラグインのprestissimoを組み合せることで、Composerが効率よく通信できるようになり、環境によっては著しい高速化の効果が得られます。
↓packagist.jpを登録(日本国内の鯖を見に行くと物理的に近い距離で通信するようになって速いよ)
↓Composerプラグイン(prestissimo; curl拡張使ってるから、並列リクエストしたりKeep-aliveが効いたりの積み重ねで速くなるよ)
通常はそこまで気にしなくていいことではありますが…
同時に大量の鯖にデプロイするような構成の場合は`git pull`だけで輻輳するような場合もあるらしいって[世界展開する大規模ウェブサービスのデプロイを支える技術 / YAPC::Asia Tokyo 2015 // Speaker Deck](https://speakerdeck.com/hatena/yapc-asia-tokyo-2015)で言ってたので、このような場合は愚直にやると逆に性能が劣化する可能性もあるのかもしれません。まあ、そのような場合はどちらにしろくふうが求められますよね><
グローバルにパッケージをインストールする
Composer用語でのglobal
とは「特定のプロジェクトに依存しない」程度の意味ですが、実はデフォルトでホームディレクトリに置かれる、ただの一個のプロジェクトです。何を言ってるのかわからないひとは、この説明は気にしなくてもいいです。
気をつけるべきは「グローバルにインストールしたからといってプロジェクトの依存関係として利用できるわけではない」ことです。グローバルと個々のプロジェクトはまったく無関係です。
composer
の利用方法として最初に説明するのですが、実のところグローバルに何かをインストールすべきことはあまり多くはありません。
ここでは、PHPのREPL/対話シェル(つまり、RubyのIRBとかPryみたいなやつ)であるPsySHをインストールしてみます。詳しくは、PHPを「シェル化」する [psy/psysh] - 超PHPerになろうとか、WEB+DB PRESS Vol.96に書きました。 (これは商業的宣伝なのでガイドライン違反なのかもしれませんね>< いまから売れても私には一銭も入りませんが)
さて、インストールしてみます。
composer global require psy/psysh
Changed current directory to /Users/megurine/.composer
Using version ^0.8.3 for psy/psysh
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 6 installs, 0 updates, 0 removals
- Installing jakub-onderka/php-console-color (0.1) Loading from cache
- Installing jakub-onderka/php-console-highlighter (v0.3.2) Loading from cache
- Installing dnoegel/php-xdg-base-dir (0.1) Loading from cache
- Installing nikic/php-parser (v3.0.5) Loading from cache
- Installing symfony/var-dumper (v3.2.8) Loading from cache
- Installing psy/psysh (v0.8.3) Loading from cache
symfony/var-dumper suggests installing ext-symfony_debug ()
psy/psysh suggests installing ext-pdo-sqlite (The doc command requires SQLite to work.)
psy/psysh suggests installing hoa/console (A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit.)
Writing lock file
Generating autoload files
最初のChanged current directory to /Users/megurine/.composer
が目立ちますね。これは私のmacOSのホームディレクトリなので、ls $HOME/.composer
で中身を覗くことができます。
さらにその中にある$HOME/.composer/vendor/bin/
を覗いてみますね。
ls -la $HOME/.composer/vendor/bin/
total 44
drwxr-xr-x 13 megurine staff 442 2017-05-10 05:31:36.000 .
drwxr-xr-x 43 megurine staff 1462 2017-05-10 05:31:37.000 ..
lrwxr-xr-x 1 megurine staff 27 2017-05-10 00:53:36.000 apigen -> ../apigen/apigen/bin/apigen
lrwxr-xr-x 1 megurine staff 28 2017-04-27 10:47:00.000 laravel -> ../laravel/installer/laravel
lrwxr-xr-x 1 megurine staff 34 2017-02-11 13:58:07.000 pdepend -> ../pdepend/pdepend/src/bin/pdepend
lrwxr-xr-x 1 megurine staff 17 2017-04-19 00:07:44.000 phan -> ../etsy/phan/phan
lrwxr-xr-x 1 megurine staff 33 2017-05-10 05:31:36.000 php-parse -> ../nikic/php-parser/bin/php-parse
lrwxr-xr-x 1 megurine staff 39 2017-05-10 00:44:45.000 phpcbf -> ../squizlabs/php_codesniffer/bin/phpcbf
lrwxr-xr-x 1 megurine staff 38 2017-05-10 00:44:45.000 phpcs -> ../squizlabs/php_codesniffer/bin/phpcs
lrwxr-xr-x 1 megurine staff 28 2017-02-11 13:58:08.000 phpmd -> ../phpmd/phpmd/src/bin/phpmd
lrwxr-xr-x 1 megurine staff 26 2017-05-10 00:43:48.000 phpunit -> ../phpunit/phpunit/phpunit
lrwxr-xr-x 1 megurine staff 22 2017-05-10 05:31:36.000 psysh -> ../psy/psysh/bin/psysh
lrwxr-xr-x 1 megurine staff 25 2017-04-19 00:07:44.000 tocheckstyle -> ../etsy/phan/tocheckstyle
私はPsySH以外にもいくつもツールを入れてるので量がそれなりにありますが、どれも実行権限がついたシンボリックリンクです。なので、さきほどと同様にPATH
を通してやればコマンドが実行できるようになります。
以下のシェルコマンドはBashまたはZ Shell(zsh)が前提です。
# 一時的に追加する場合
% PATH=${COMPOSER_HOME:-$HOME/.composer}/vendor/bin:$PATH
# Z Shellの場合
% echo 'PATH=${COMPOSER_HOME:-$HOME/.composer}/vendor/bin:$PATH' >> ~/.zshrc
# GNU Bashの場合
% echo 'PATH=${COMPOSER_HOME:-$HOME/.composer}/vendor/bin:$PATH' >> ~/.bashrc
シェルでPATH=${COMPOSER_HOME:-$HOME/.composer}/vendor/bin:$PATH
を実行してみて、psysh
コマンドが動けば大成功です。
あとがき
ねむいなねむいです。
最近は「PHPユーザーズ (日本語)」ってチャットに #composer
ってchannelもあって、業務でComposerを運用してるひとたちも集まってる(たぶん)。無料サポートではないですけど、相談に乗ることはできます。きっと。
あとこの記事は、先週ガイドラインとかでわーきゃー騒がしかった時期に書いてました。いま投稿するのは特に理由はなくて、途中で書くのに飽きたのでだらだら書いてたら今までかかったのと、いまも飽きてるので忘れないうちに投稿することにしました。飽きなければ、プロジェクトに導入する方も書きます。