Phan/PHPStan/Psalm を VSCode で使ってみるメモ

普段 PHP のコードは PhpStorm で書いているので VSCode で PHP のコードを開くことはほとんどありませんが、たまに PhpStorm では OK なのに Phan などの静的解析ではエラーになることがあり、その修正のために何度も phan コマンドを叩くのは辛いので(なんせ時間かかる)、Phan などの静的解析だけでも VSCode で動かせられると便利かも、と思って試してみました。

PHP は WSL 上で、VSCode は Windows 上で、という歪な構成だったので、一部ハマりどころがありました。VSCode なら Remote WSL で簡単に WSL 上でも実行できるのでその方が良いかもしれません。

Phan

拡張は下記を使いました。

Phan 本体が拡張にバンドルされているので composer でインストールしておく必要はありません。

別の Phan を使うことも可能ですが、設定の phan.phanScriptPath に絶対パスで指定する必要があります。指定するパスは php で実行されるので phan.pharvendor/phan/phan/phan を指定します(シェルスクリプトや phan.bat とかではなく)。

また、設定の phan.analyzedProjectDirectory でプロジェクトのパスを絶対パスで指定する必要があります。ワークスペースのルートからの相対とかでは指定出来ません。

どちらも絶対パスしか通らないのがちょっと面倒です。扱いやすくするための PR はあるようですがマージされていません。

これさえ気にならなければ快適に動作します。Windows でも問題ありません。

と、思ってたんですが、Windows だと開くプロジェクトによってはまったくチェックが働かないことがありました。見た感じ Phan の問題っぽいので PR を投げておきました。そのうち修正されるかもしれません。

と思ってたら、それじゃダメとのことで別の修正の PR がマージされました。

PHPStan

複数の拡張が見つかりました。

calsmurf2904.vscode-phpstan 以外は動作しました。mandy91.vscode-phpstan と levacic.vscode-phpstan は calsmurf2904.vscode-phpstan のフォークです。

breezelin.phpstan はステータスバーに表示される phpstan の状態の表示位置が好みではなかったのと、levacic.vscode-phpstan は README によると mandy91.vscode-phpstan のちょっとしたハック(phpstan.neon で解析レベルを指定しても無視されてしまい拡張の設定で指定した解析レベルが強制されてしまうのを改善しているもよう)であって依存パッケージなどが最新に追従していない、とのことなので mandy91.vscode-phpstan を使ってみました。

ワークスペースまたは COMPOSER_HOME(~/.composer とか %APPDATA%/Composer とか)の vendir/bin に、または PATH 環境変数に phpstan コマンドが必要です。composer でプロジェクトのローカルなり global なりにインストールしておけば大丈夫なのですが、Windows の場合は phpstan.bat が必要なので Windows 上(cmd.exe とか)で composer を実行する必要があります(WSL 上で実行すると phpstan.bat が作成されないし phpstan も Windows 側からは読めないシンボリックリンクになってしまう)。

設定 phpstan.path で別の phpstan も指定できます。ただしシェルから実行されるので Windows の場合は phar を指定しても駄目で phpstan.bat を指定する必要があります。Linux なら実行属性がついていれば phar でも大丈夫です。

Phan や Psalm の拡張と比べると PHPStan は VSCode 上で入力確定してから結果が反映されるまでに結構なラグがあります。Phan や Psalm はエディタと連携用の LanguageServer が常駐するのに対して PHPStan だと毎回 phpstan コマンドが実行されているためでしょう。巨大なプロジェクトだと VSCode 上でリアルタイムにエラー表示するのはやや辛そうです。

Psalm

拡張は下記を使いました。

Windows では上手く動作しませんでした。WSL 上で VSCode を実行すれば快適に動作しました。

Psalm はデフォルトでワークスペースの vendor/vimeo/psalm/psalm-language-server が使用されます。設定 psalm.psalmScriptPath で別のファイルも指定できます。ファイルは絶対パスでもワークスペースの相対パスでも指定できます。ワークスペースに複数のルートディレクトリがあるときは先頭のルートディレクトリから探されます。

指定したファイルは php コマンドで実行されます。なので指定するのは php スクリプトや phar です。シェルスクリプトや bat ファイルではありません。また、指定するのは psalm-language-server です。psalm ではありません。

psalm は phar が提供されていますが psalm-language-server の phar はありません。ので phar ではなく composer require でインストールする必要があります。もしくは phar でも psalm.phar --language-serverpsalm-language-server が実行されるので、次のようなスクリプトを噛ませば phar でも OK です。

<?php
$_SERVER['argv'] = array_merge(
    array_slice($_SERVER['argv'], 0, 1),
    ['--language-server'],
    array_slice($_SERVER['argv'], 1),
);
require __DIR__ . '/../vendor/pharhub/psalm/psalm.phar';

むしろ拡張の方で --language-server オプションを自動でつけてくれればいいと思うので PR を投げておきました。

Windows で動作しない理由ですが、VSCode から拡張を経由して LanguageServer に渡されれるファイルパスで大文字小文字が混在することが問題のようなので PR を投げておきました。そのうち修正されるかもしれません。

と思ってたらマージされていました。次のリリースでは修正されています。

さいごに

Phan と Psalm は LanguageServer がサポートされているため、LanguageServer が起動して全体の解析が終わればそれ以降は軽快に動作します。

ただ Phan はプロジェクトが大きくなるとそれでも動作がだいぶもっさりしてきました。入力してから反映されるまでに数秒はラグがあります。

Psalm はプロジェクトが多少大きくなってもわりと軽快でした。ただ、LanguageServer が開始してから利用可能になるまですごい時間がかかります。ちょっとお茶でも入れてこようかと思いました。

PHPStan は LanguageServer がサポートされていなくて phpstan コマンドが毎回実行されているので、小さいプロジェクトでも結構もっさりです。が、プロジェクトが大きくなってくると Phan とそれほど大差なくなりました。また、LanguageServer が利用可能になるのを待つためにお茶を入れてくる必要もありません。

なぜか Phan も Psalm も似たような原因で Windows での動作に支障がありました(ファイル名の大文字小文字のケースの問題)。いずれも修正がマージされているので次のリリースでは修正されています。

PHPStan は単にコマンドを実行するだけのシンプルな動作のためか、Windiws でも特に問題なく動作しました。

Phan はプロジェクトのディレクトリを絶対パスで設定する必要があるのが煩雑です。たいていの場合はワークスペースのルートがプロジェクトのルートなので自動で検出してほしいところです。

PHPStan や Psalm はプロジェクトに composer でインストールしていて phpstan.neon や psalm.xml で設定済なら拡張は何も設定しなくても動作します。phar を使おうとすると一工夫必要です。

Phan は拡張が動作している最中に VSCode 上でなにも表示されないので動いているのかどうか不安になることがあります。特に LanguageServer の初回の解析中とか、終わってるのか終わってないのか見た目ではわかりません。

PHPStan や Psalm は状態がステータスバーに表示されます。Psalm は何もしていなくても常時ステータスバーを「Psalm:running」を専有してしまいますが、設定で解析の実行中だけ表示するようにもできます。個人的にはその方が好きです。PHPStan は元々解析中だけステータスバーに状態が表示されます。

主観ですが、いまのところ VSCode で使うなら、起動してから有効になるまでの時間を気にしないなら Psalm が、起動してから直ぐに有効になって欲しいなら PHPStan が良さそうです。