Pharパッケージ管理ツール「Phive」を試す

株式会社エイチームライフスタイルでWebエンジニアをしています、@okonomiと申します。
[Ateam Lifestyle x cyma Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ateam-lifestyle-cyma) 11日目は、「Phive」について書いてみたいと思います。

# この記事で書くこと

- Phiveって何？なんで必要なの？
- Phiveの基本的な使い方

# こんな人におすすめ

- ComposerでphpstanなどのPHP製ツールをインストールしたら依存関係の衝突で苦労した
- .pharファイルをダウンロードしたけど管理するのが面倒

# Phiveって何？

Phiveとは、Pharを管理するパッケージマネージャです。

https://phar.io/

Pharとは何かというと、複数のファイルからなるPHPプログラムを.pharとしてひとつのファイルにまとめる仕組みです。
公式ドキュメントがわかりやすいので詳しくはそちらをご覧ください。

http://php.net/manual/ja/book.phar.php

.pharファイルとして提供されているPHP製ツールをインストールしたりアップデートしたり一元管理してくれるのがPhiveです。

## なんでPhiveが必要なの？

PHP製ツールをインストールするぞ！となったとき、方法としては

1. Composerでインストール
2. .pharファイルをダウンロード（提供されている場合）

どちらかになります(MacならHomebrewを使う手もありますが、ここでは置いておきます）。

Composerでインストールする場合、そのツールの依存関係がPHPアプリケーションに持ち込まれます。
そのとき、アプリケーションとツールの依存関係が競合してしまうことがあります。

例えば、アプリケーションがsymfony/console 3.0をインストールしている状態で、

```
$ composer require symfony/console:~3.0.0
```

phpstanを入れようとすると、競合します。

```
$ composer require --dev phpstan/phpstan
Using version ^0.10.6 for phpstan/phpstan
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for phpstan/phpstan ^0.10.6 -> satisfiable by phpstan/phpstan[0.10.6].
    - phpstan/phpstan 0.10.6 requires symfony/console ~3.2 || ~4.0 -> satisfiable by symfony/console[3.2.x-dev, 3.3.x-dev, 3.4.x-dev, 4.0.x-dev, 4.1.x-dev, 4.2.x-dev, 4.3.x-dev, v3.2.0, v3.2.0-BETA1, v3.2.0-RC1, v3.2.0-RC2, v3.2.1, v3.2.10, v3.2.11, v3.2.12, v3.2.13, v3.2.14, v3.2.2, v3.2.3, v3.2.4, v3.2.5, v3.2.6, v3.2.7, v3.2.8, v3.2.9, v3.3.0, v3.3.0-BETA1, v3.3.0-RC1, v3.3.1, v3.3.10, v3.3.11, v3.3.12, v3.3.13, v3.3.14, v3.3.15, v3.3.16, v3.3.17, v3.3.18, v3.3.2, v3.3.3, v3.3.4, v3.3.5, v3.3.6, v3.3.7, v3.3.8, v3.3.9, v3.4.0, v3.4.0-BETA1, v3.4.0-BETA2, v3.4.0-BETA3, v3.4.0-BETA4, v3.4.0-RC1, v3.4.0-RC2, v3.4.1, v3.4.10, v3.4.11, v3.4.12, v3.4.13, v3.4.14, v3.4.15, v3.4.16, v3.4.17, v3.4.18, v3.4.19, v3.4.2, v3.4.20, v3.4.3, v3.4.4, v3.4.5, v3.4.6, v3.4.7, v3.4.8, v3.4.9, v4.0.0, v4.0.0-BETA1, v4.0.0-BETA2, v4.0.0-BETA3, v4.0.0-BETA4, v4.0.0-RC1, v4.0.0-RC2, v4.0.1, v4.0.10, v4.0.11, v4.0.12, v4.0.13, v4.0.14, v4.0.15, v4.0.2, v4.0.3, v4.0.4, v4.0.5, v4.0.6, v4.0.7, v4.0.8, v4.0.9, v4.1.0, v4.1.0-BETA1, v4.1.0-BETA2, v4.1.0-BETA3, v4.1.1, v4.1.2, v4.1.3, v4.1.4, v4.1.5, v4.1.6, v4.1.7, v4.1.8, v4.1.9, v4.2.0, v4.2.0-BETA1, v4.2.0-BETA2, v4.2.0-RC1, v4.2.1] but these conflict with your requirements or minimum-stability.
```

これは、phpstanが依存しているsymfony/consoleが3.2以上か4.0以上で、アプリケーションが依存しているのは3.0なので整合性が取れないためです。

この場合の解決策としては、アプリケーションが依存するsymfony/consoleのバージョンを3.2以上に上げることですが、アプリケーションの動作に必要ない外部ツールのために依存ライブラリのバージョンを上げるのもおかしな話です。

また、もしたまたま競合が起こらなかったとしても、依存関係は複雑になるため、競合する可能性が高まってしまいます。

じゃあということで、.pharファイルをダウンロードして使う場合ですが、ダウンロードした.pharファイルをどう管理するのかちょっと考えないといけません。
.pharをgitリポジトリに入れるのはちょっといやだな、となると、開発メンバーに各自で.pharファイルをダウンロードしてもらわないといけなくなったりします。

そのあたりの.pharファイルの管理の面倒くささを解消してくれるのがPhiveです。

## 誰が使ってるの？

後述するPhiveの管理ファイル（phive.xml）が含まれているリポジトリがどれだけあるか、GitHubで検索してみました。

https://github.com/search?q=filename%3Aphive.xml+path%3A%2F&type=Code

100個ないくらいなので、まだ広く使われてるとは言えなそうです。

## 誰が作ってるの？

https://github.com/orgs/phar-io/people

Organizationを見ると、PHPUnitの作者であるsebastianbergmannさんがいます。
ほかにもtheseerさんはドキュメントジェネレータ「[phpdox](http://phpdox.de/)」の作者の方です。

みなさん所在地がドイツなので、ドイツのPHPコミュニティで生まれたプロジェクトなのでしょうか…？

また、最初のコミットが2015年3月21日で、そこから現在まで継続的に開発が続けられています。
https://github.com/phar-io/phive/commit/444d27e3d6681a95444bb0d34beaf3d01109c3c7

## Phiveは何を提供してくれるの？

Phiveは主に3つの働きがあります。

1. パッケージマネージャ
2. ビルドツール
3. プラットフォーム

Phiveはパッケージを管理する以外にも、ツール開発者が.pharファイルをビルドするコマンドを用意しています。
また、ツール開発者がツールを登録する場所を用意しています。

今回はパッケージマネージャに絞って記事を書きます。

# Phiveを使ってみる

前置きが長くなりましたが、ここから実際にPhiveを使ってみます。

## セットアップ

まずはPhiveをセットアップします。

[公式サイト](https://phar.io/)の手順をそのまま実行します。

```
$ wget -O phive.phar https://phar.io/releases/phive.phar
$ wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
$ gpg --keyserver pool.sks-keyservers.net --recv-keys 0x9D8A98B29B2D5D79
$ gpg --verify phive.phar.asc phive.phar
$ chmod +x phive.phar
$ sudo mv phive.phar /usr/local/bin/phive
```

ただし最後の`phive`の置き場所はお好みで。
自分は`~/bin`にパスを通しているのでそこに置きました。

```
$ mv phive.phar ~/bin/phive
```

軽く動作確認します。

```
$ phive version
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors
```

バージョン番号が表示されれば正常に動作しています。

ついでに、お試しで使うためのディレクトリを適当に作っておきます。
名前は何でも結構です。ここでは`phize-sandbox`としました。

```
$ mkdir phize-sandbox
$ cd phize-sandbox
```

## パッケージをインストールする

さっそくパッケージをインストールしてみます。

```
$ phive install phpunit
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors
 Linking /Users/okonomi/.phive/phars/phpunit-7.5.0.phar to /Users/okonomi/src/local/phive-sandbox/tools/phpunit
```

インストールされました。

```
$ tree .
.
├── phive.xml
└── tools
    └── phpunit -> /Users/okonomi/.phive/phars/phpunit-7.5.0.phar
```

Phiveは、デフォルトでは`~/tools`ディレクトリ以下にコマンドをインストールします。
コマンドはシンボリックリンクになっていて、実体は`~/.phive`ディレクトリに置かれます。

シンボリックリンク張られるのがいやなら、`--copy`オプションをつけると実体が`tools`内に配置されます。

```
$ phive install phpunit --copy
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors
Copying phpunit-7.5.0.phar to /Users/okonomi/src/local/phive-sandbox/tools/phpunit
```

インストールディレクトリを`tools`から変えたいなら`--target`オプションでディレクトリを指定できます。

```
$ phive install phpunit --target bin
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors
Linking /Users/okonomi/.phive/phars/phpunit-7.5.0.phar to /Users/okonomi/src/local/phive-sandbox/bin/phpunit
```

その他のオプションは`phive help`で確認できます。サブコマンド個別のヘルプはなさそうです。

```
$ phive help
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors

Usage: /Users/okonomi/bin/phive [global-options] <command> [arguments]
(略)
install [--target bin/] <alias|url> [<alias|url> ...]
    Perform installation of a phar distributed application or library

    alias/url                    Installation via github profile/project, phar.io alias
                                 or explicit download form given URL

    -t, --target                 Set custom target directory for the PHAR

    -c, --copy                   Copy PHAR file instead of using symlink
    -g, --global                 Install a copy of the PHAR globally (likely requires root privileges)
        --temporary              Do not add entries in phive.xml for installed PHARs
        --trust-gpg-keys         Silently import these keys when required (separated by comma)
        --force-accept-unsigned  Force installation of unsigned phars
(略)
```

## いろんなパッケージをインストールしてみる

インストールできるパッケージは`phive list`で確認できます。

```
$ phive list
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors

List of phar.io resolved aliases known to your system:
* infection
* phpab
* phpcpd
* phpdox
* phploc
* phpunit
* phpbu
* dephpend
* phpdocumentor
(略)
```

インストールできるパッケージはこちらのファイルで管理されています。

https://github.com/phar-io/phar.io/blob/master/data/repositories.xml

パッケージの追加はPull Requestをすれば良いようです。

https://github.com/phar-io/phar.io/search?q=repositories.xml&type=Issues

もしリストにないパッケージをインストールしたい場合は、.pharファイルのURLを直接指定するか、githubプロジェクト名を指定するとインストールできます。

https://phar.io/how-it-works.html

```
$ phive install https://phar.phpunit.de/phpunit-7.5.0.phar
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors
Linking /Users/okonomi/.phive/phars/phpunit-7.5.0.phar to /Users/okonomi/src/local/phive-sandbox/tools/phpunit
```

## インストール済パッケージの管理

パッケージをインストールすると、カレントディレクトリに`phive.xml`というファイルができています。

```xml:phive.xml
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpunit" version="^7.5.0" installed="7.5.0" location="./tools/phpunit" copy="false"/>
</phive>
```

これはPhiveでインストールしたパッケージを記録しているファイルです。Composerでいうところの`composer.json`ですね。
このファイルをgitリポジトリに含めておけば、新しくgitリポジトリをcloneしたときもそのプロジェクトで使用しているツールをすばやくセットアップすることができます。このへんの理屈もComposerと同じです。

その場合は、`phpvie install`を引数無しで実行します。

```
$ phive install
Phive 0.12.1 - Copyright (C) 2015-2018 by Arne Blankerts, Sebastian Heuer and Contributors
Linking /Users/okonomi/.phive/phars/phpunit-7.5.0.phar to ./tools/phpunit
```

基本的な使い方は以上です。

他に`update`や`remove`など必要なコマンドはひととおり用意されています。
詳しくは`phive help`でヘルプを確認してみてください。

# まとめ

Phiveをざっと試してみました。

.pharファイルをコマンド一発でシュッと配置できて、ComposerでPHP製ツールをインストールする方法に比べて余計な依存関係が追加されることもなく、それでいて`phive.xml`でインストール情報を管理できるPhive、自分はなかなかいいんじゃないかと思いました。

プロジェクト本体のコードには影響を及ぼさないし、Composerと共存させて使うこともできるので、導入のハードルも低いのではないかなと思います。
（CIで使うときにどうするかは調べられなかったのでそこだけ懸念ではありますが…[phpboxの.travis.yml](https://github.com/theseer/phpdox/blob/master/.travis.yml#L18-L25)が参考になりそう）

PHP製の外部ツールの管理に困っていた方は一度試してみてはいかがでしょうか。

[Ateam Lifestyle x cyma Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ateam-lifestyle-cyma)の12日目は@kazenomachiさんです。よろしくおねがいします！

# お知らせ

エイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/

# 参考

今回書かなかったパッケージ提供者から見たPhiveについて、参考になりそうな資料があったので挙げておきます。

- https://hollo.me/talks/phar-better-tools.html
    - Holger Woltersdorfという方が[PHP USERGROUP DRESDEN](https://phpug-dresden.org/)のMeetupで発表されたときの資料です。.pharファイルを作るときのツールについてまとめられています。
- https://speakerdeck.com/thomasweinert/build-automation-with-phive-and-phing
    - どういった背景のスライドか分からなかったのですが、PhiveとPhingを使って.pharファイルを作る手順についてまとめられています。