今さらComposer

ざっくりComposer

もう紹介記事は溢れているのでいちいち書く意味を感じないが、とりあえず。

  • PHP 5.3 以降で利用可能
  • package の依存管理ができる
  • Pear を含む複数の種類の package に対応している
  • Bundler のように project 単位での package の管理を支援してくれる(project 配下への download と autoloader)
  • Composer 独自の package 形式がある
  • packagist.org というデフォルトの repository がある(rubygems.org相当)

Composerという言葉の指す範囲

Bundler には Rubygems が package で Bundler が依存解決、という分かりやすい機能の対応関係があるが、Composer の場合は

  1. 依存解決を行う Composer
  2. Package を作る Composer

と、どっちも Composer が担っている。(Bundler もすでに bundle コマンドで gem が作れてしまうので、実装上は分離していても実際の利用上は分かりにくいのかもしれない。)

Composer のキモは composer.json だが、上に書いたような状態のため、Bundler と Rubygems の関係で言うところの Gemfile も .gemspec もどっちも composer.json に記述するという格好になってしまっている。

正直、この全部入りになってしまう感じが悪い意味で PHP っぽいなと感じる。また、JSON という汎用のフォーマットで書くようにしているのも混乱に拍車を掛けている気がする。パッと見でどっちの目的の composer.json なのか分からない。

Composerでinstallできるもの

上に書いた 2 の Package に相当する部分は間口が広く、

  • Pear
  • Pear2
  • Archive
  • VCS

に対応しているので、昔から使っている Pear Package があるのであれば、composer.json で repositories と require に書いてあげるだけでこれを install することができる。例えば Pear の HTTP であれば以下のような感じ。

{
  "repositories": [
    {
      "type": "pear",
      "url": "http://pear.php.net"
    }
  ],
  "require": {
    "pear-pear.php.net/HTTP": "*"
  }
}

これで composer install すると

vendor/pear-pear.php.net/HTTP/

以下に HTTP.php が入る。

当然だが Pear package を入れ始めると例によって Archive_Tar だの Structures_Graph だのも漏れなくついてくる。

PHP 5.3以降で新しく何かを作るならComposerを使うのが楽

基本的には Composer は Pear package などを使う方法を推奨しているわけではなく、packagist.org での composer package の公開を前提にしている。これはちょうど Ruby で言う rubygems.org のようなものだが、Bundler の Gemfile と違い、repositories に packagist.org を記述するという手間は必要なく、決め打ちで実行してくれる。

ただ、packagist.org に公開していなくても自作のコードを composer で install させることはできるので、以下にやったことを整理しておく。

Composer対応

  • composer.json を作って repository に入れるだけ
  • tag を正しく打っていればバージョンとして使われる(これは VCS 上の tag の話であって composer.json は関係ない)
  • 必要最低限は name だけでも ok(もちろん description などはあるべきだけど)
    • name は "vendor name/project name" の書き方で

cf. https://getcomposer.org/doc/04-schema.md#name

Composerでinstall

  • install する側の composer.json から composer 対応 repository を追加したうえで require してやる
  • 例えば手元の git repository なら url は local の filesystem になる

こんな感じ。

{
  "repositories": [
    {
      "type": "vcs",
      "url":  "/path/to/repository"
    }
  ],
  "require": {
    "vendor/project": "*"
  }
}

Bundler で言うところの

gem 'foo', :path => '/path/to/repository'

に似ているが、require の中で直接 repository の path を書くことはできない。

公開してよいものなら packagist に submit して install する側の composer.json を書き換えてやるとよい。

まっさらからのComposerまとめ

本当にまっさらの状態から自前で用意している依存コードを Composer で管理したい場合、

  • Composer 管理対象にしたい repository に composer.json を作って入れる
  • Composer で便利機能を install したい repository にも composer.json を置いて vendor 以下に依存コードを入れる

という二つの作業が必要。

過渡期の過ごし方

PHP 5.3 未満のコードにも 5.3 以上のコードにも対応する必要がある場合、当然だが Composer は万能薬にはならない。

この場合は

  • 依存されるライブラリなどの側のコードに composer.json を用意しつつ
  • PHP 5.3 未満の環境では Pear package や丸ごとコピーなどで対応する

必要がある。

例えば Pear package を利用して 5.1 環境に対応しつつ Composer で 5.3 以降の環境にも対応しようとする場合を考える。

まず Pear package で言うバージョンと Composer で言うバージョンを合わせるか合わせないかの判断が必要になってくる。もちろん合っている方が分かりやすいと思うが、Pear package が見ているバージョン情報はファイル名と package.xml 内のバージョン情報であり、Composer が見ているのはファイル名と VCS の tag である。これまで tag をちゃんと活用していない場合はここが一つネックとなる。

また metadata も別個に保持する必要がある。まぁ初回以降はそれほど大きな手間ではないが、package.xml と composer.json の両方に metadata を用意する必要がある。

やや煩雑だが、この手間を掛けておく価値はあると思う。既存の資産の Composer 対応は思った以上に簡単で、非公開のコード資産でも Composer 管理に移行してしまった方がいろいろ楽ができる。少なくとも VCS とうまく連携できるところはとてもイマドキで、Composer を知ったらいちいち package を作ったり channel サーバ立てたりしていた Pear 時代にはもう戻れないし、Composer が Pear package の install にも対応しているところは migration のためにとてもよい機能だと思う。

これでようやく手で zip や tarball 取って来て配置するという石器時代の手法にオサラバできるようになったんだな…。しみじみ。(自分の管理している範囲のお仕事のコードは自前で Pear package にして管理してたけど。これはこれで packaging と deploy が面倒だなと思っていたのであった。)

More