PHPStanをどうやってインストールするか
PHPStanはPHPの静的解析ツールです。現代のPHPerはみんな使ってるよ。
……ところで、みなさんはPHPStanをどうやってインストールしているのでしょうか。
PHPStan開発者のOndřej Mirtesは次のように述べています。
多くの場合において、Ondřejの言う通りcomposer require --dev
が最善のインストール方法です。
この記事では、なぜそれが推奨のインストール方法だと言えるのか、どのような場合に別の選択肢が候補に挙がるのかを解説します。
あと、この記事はPHPカンファレンス沖縄2022でPHPStanの使い方を説明するのにインストール方法まで説明する時間がとれないので書きました。
あらかじめ知っておきたいこと
事前知識: PHPStanパッケージの構造
PHPStanのリポジトリはGitHubでは以下の2リポジトリに分かれています。
-
https://github.com/phpstan/phpstan
- PHPStanのビルド済みパッケージ(Pharアーカイブ)を配布している
- issueではPHPStanのバグ報告や機能追加要望も受け付けている
- phpstan.orgのコンテンツはここで管理されているので、ドキュメントの修正などはこちらに送る
-
https://github.com/phpstan/phpstan-src
- PHPStanのソースコードをホストする
- 機能追加や修正のプルリクエストはこちらに送る
- issueは無効化されているのでphpstan側に送る
Composerの標準リポジトリであるPackagistでphpstan/phpstanとして配布されているのは前者のリポジトリです。
PHPの「ビルド済みパッケージ」とはどういうことでしょうか。実際にComposerでインストールされるディレクトリ一式を見てみましょう。
vendor/phpstan/phpstan/
├── LICENSE ← ライセンスファイル
├── README.md ← ドキュメント(README)
├── bootstrap.php ← PHPStanをクラスとして使いたいときに読み込むファイル
├── composer.json ← Composer パッケージ設定ファイル
├── conf
│ └── bleedingEdge.neon ← bleedingEdgeを有効化するための設定ファイル
├── phpstan ← PHPStan実行スクリプト
├── phpstan.phar ← PHPStanのクラス一式がパッケージされたアーカイブ
└── phpstan.phar.asc ← PGP署名ファイル
なんとPHPStan 1.8.2時点でインストールされるファイルはたったのこれだけです。Pharという概念に馴染みのない方はPHPマニュアルの「Phar」の記事を「はじめに」だけでも読んでください。
要はPHPスクリプトをzipのような一個のアーカイブファイルにまとめたものです。PHPStanの実装と依存ファイル・依存パッケージはすべて、この1ファイルに格納されています。
Pharファイルを作成する過程で以下の処理も行われています。
これにより、PHPStanで使っている依存パッケージ(ライブラリ)は名前空間が隔離され、ほかのアプリケーションと衝突しないようになっています。
事前知識: 拡張とextension-installer
PHPStanは「拡張(extension)」によって通常の型宣言を読み取るだけでは実現できない型付けやフレームワーク固有のルールなどを検査できるようになります。
フレームワークやライブラリ用の公式およびサードパーティの拡張ライブラリはこちらの記事をお読みください。
拡張によってどのようなことが可能なのかは以下の記事を読むと良いでしょう。
さて、上の記事でも言及されていますが、拡張を有効化するには拡張ごとの設定ファイルをincludesに追加する必要がありますが、phpstan/extension-installerを使うと自動で有効化できます。
どのような場合に使うべきで、どのような場合に使えないかは上記記事に書いてあるので、必要に応じて追加するなり、各拡張のREADMEを読んで設定するなりしておいてください。私としては基本はextension-installerで有効化するのがおすすめなので、以後そのていで書きます。
composer require --dev
[RECOMMENDED] 前述した通り、PHPStan作者のOndřej Mirtesはこの方法だけを推奨しています。
PHPStanユーザーマニュアルのGetting Startedで紹介されているのもcomposer require --dev
です。
一般に、QAツール類(たとえばPHP-CS-Fixer)はいくつかのライブラリへの依存があり、composer require --dev
でインストールするとプロジェクトの依存関係と衝突してしまい、アップデートの障壁になってしまうことがあります。
一方、PHPStanは先に説明した通り依存パッケージの名前空間を隔離しており一切のパッケージ依存がないので、そのような懸念もなく依存関係として追加できます。
インストール方法
composer
はPHPの実行環境に併せて適宜 docker-compose exec php composer ...
とか php composer.phar ...
とか sail composer ...
とかそういう感じに読み替えてください。
composer require --dev -W phpstan/phpstan phpstan/extension-installer
Larastanを同時に使いたい場合は同時に追加します。
composer require --dev -W phpstan/phpstan phpstan/extension-installer nunomaduro/larastan
composer require
ではパッケージのバージョンを省略するとインストール可能な最新のバージョンが導入されるので、PHPStanや拡張をアップデートしたい場合にも同じコマンドを使います。
使いかた
OSにインストールされたPHPを直接使える場合は以下のように実行します。
./vendor/bin/phpstan analyze ...
プロジェクトの実行環境をDockerまたはdocker-composeで構築していて、既にコンテナが起動している場合は以下のように実行します。
docker exec <service_name> vendor/bin/phpstan analyze ...
docker-compose exec <service_name> vendor/bin/phpstan analyze ...
Laravel Sailを使っている場合はsail vendor/bin/phpstan analyze ...
みたいな感じで起動できると思いますが、私は試していません。
この方法の利点
- 開発メンバー全員の環境に確実に導入でき、PHPStanのバージョンを合わせやすい
- 通常のPHPスクリプトとしてホスト環境のPHPまたはDockerなどで実行できる
この方法を適用できない条件
- プロジェクトのPHPバージョンが7.2未満
-
composer
のplatform
が7.2未満の設定になっている - DockerコンテナのPHPランタイムが7.2
- 環境が仮想化されておらず、PHP 7.2以上をインストールすることもできない
-
- プロジェクト責任者との合意がとれておらず、Composerの依存に追加できない
composer global require
Composerはパッケージごとに依存を管理するものですが、composer globalは特定のプロジェクトとは独立したディレクトリにComposerパッケージをインストールできます。
インストール方法
composer
はPHPの実行環境に併せて適宜 php composer.phar ...
とか読み替えてください。
composer global require --dev -W phpstan/phpstan phpstan/extension-installer
composer global require
でも通常と同様にパッケージのバージョンを省略するとインストール可能な最新のバージョンが導入されるので、PHPStanや拡張をアップデートしたい場合にも同じコマンドを使います。
歴史的経緯により、composer global
を実行した結果は以下のディレクトリのどこかに配置されています
-
~/.config/composer
- 比較的最近Composerをインストールした人はこっち
-
~/.composer
- 割と前からComposerを使っていて最新新規インストールとかしてない人はこっち
あとは$COMPOSER_HOME
という環境変数で制御することもできますが、基本的に勝手にセットされることはないのでこの2パターンを想定しておけばいいと思います。Composerでインストールされたスクリプトはこれらのディレクトリの直下のbin
ディレクトリに配置されるので、そこにPATHを通せば通常のコマンドとして使えます。
よくわかんないひとはcomposer global show
で検索してチェック… してもいいのですが、めんどくさいので両方にPATH
環境変数を通しておくといいですね。
PATH=$HOME/.config/composer/bin:$HOME/.composer/bin:$PATH
上記の操作をしてcomposer
コマンドが起動できるようになっていれば成功です。
この方法の利点
- 検査対象のプロジェクトに変更を加えずに導入できる
- 更新頻度の少ない小規模なライブラリなどに個別の導入が必要ない
- 通常のPHPスクリプトとしてホスト環境で実行できるためDockerが必要ない
- Dockerの実行パフォーマンスが悪い環境でも使える
この方法を適用できない条件
- ホストにPHP(7.2以上)とComposerをインストールできない環境
composer-bin-plugin
composer-bin-pluginはプロジェクトのサブディレクトリに隔離されたComposerパッケージを作って、実行したいツールを隔離された依存関係としてインストールできます。この方法は、たとえばPHP 5.x、7.x、8.xをすべてサポートする必要があるライブラリなどをPHP 8.xまたは7.x環境下で開発しているといった場合に有効です。
正直これはツールを導入してサブディレクトリを切っていくだけなので、この記事での詳細な説明は避けます。
この方法の利点
- 検査対象のプロジェクトの依存関係に変更を加えずに導入できる
この方法を適用できない条件
- リポジトリ内にサブディレクトリを切ってツールを導入する権限がない
Phive
PhiveはPHPのための便利ツールをPharファイル単位でインストールできるツールです。このツールもcomposer require --dev
では依存性が混ざる問題を防ぐ問題を避けられます。
なのですが、使いやすいかは自己判断してください。
この記事を書いた時期にあった「sks-keyservers.net
の不安定性」は解決されてるかもしれません。(サーバー自体が廃止されたので)
この方法の利点
- 検査対象のプロジェクトの依存関係に変更を加えずに導入できる
- GPGでファイルの真正性を保証できる (これはComposerにはない機能)
この方法を適用できない条件
- それぞれの環境(開発者環境・CI環境)でPhiveをインストールできない場合
jakzal/phpqa
Ondřejのツイートに挙がっているので紹介だけしておきます。これはPHPのQAツール(静的解析とかテストフレームワークとか品質管理のためのツールの総称)をまとめて導入するためのDockerコンテナです。
READMEを見ると長大なテーブルがありますが、ほとんど知らないツールばかりなのではないでしょうか。……全部使いたいなら選択肢に入るのかもしれません。
結局どれを使えばいいの?
いちおう図にしてみたのですが、composer require --dev
以外は緊急避難的な方法だと思ってください。
Discussion
手元で確認した限りでは
は動かなくて
でいけました。