(中篇)PHPこの記事についてみなさんここまでついてこられていらっしゃいますでしょうか。(前篇)の続きなので、先に読んで、できれば実際に準備してから来てください。一気に後篇を書いてしまおうとも思ったのですが、前回は徹夜して書いたので本日は著しく眠いので「Psalmの続き」と「型宣言」と「Phan」の話を書いて私は寝ます。(前回の続き)さて、PsalterはPsalm同梱の修正ツールです。--issues=allで実行するとプロジェクト内のファイルが書き換えられます。Psalterに限らず、今後ソースコードを自動で書き換えるツールがありますので、実行前にGitでコミットしておいてください。{$name}!"と書いてあるので、このHello::to()は絶対に文字列を返すということがわかります。stringを付けるのは確実に安全です。$nameにするのはどうでしょうか。この操作は実際のところあまり安全ではありません。以下のようなテストを加えてみましょう。}この例は雑で、当てずっぽうで非常に書いたものです。PHPUnitを実行してみると、まあ当然失敗します。1!'だったということです。アサーションの順番を並べ変えると、以下のような出力も確認できます。真偽値のtrueは文字列として埋め込むと1になってしまうのです。ここで私たちは一つの決断を迫られれています。{$name}!"に埋め込む必要はあるのでしょうか?もちろんそれが役に立つ場面もありますが、「元気良く英語であいさつする!」というこのクラスの責務(たったいま考えました)にとっては、任意の型を値を文字列に変換するなんて機能は蛇足です。$nameにするということにしましょう。$nameという型宣言を追加することで「引数が数字だったら...」「引数が配列だったら...」「引数がオブジェクトだったら...」という可能性を全部捨てて、「$nameは文字列である」という大前提を元に処理を書けるようになります。これは自動修正ではなく、人間が自分の意思で決めることです。いうことで型をつけてみましょう。}PHP7ではdeclare(strict_types=1);を付けることで「強い型付け」が有効になります。この状態では引数に間違った型の値を渡して呼ぶとTypeErrorが発生します。予期せぬ状態のまま動き続けることを防げるのです。ここで気をつけてほしいのは、「declare(strict_types=1);はファイル単位で機能すること」「メソッド(関数)型宣言の型の強弱は呼び出し側の設定に依存すること」です。それはどういうことでしょうか。先ほどのHello::to()メソッドに数字を渡したテストはまだ残っていますので、PHPUnitを動かして確認してみましょう。int(1)が一番上に来るように、また並び換えて実行してみます。}結果はどうなるでしょうか。$subject->to(1))は通過してしまっているのです。強い型付けは機能していません。強い型付けを有効化するには、メソッドの呼び出し側にもdeclare(strict_types=1);を設定してあげる必要があります。Bag2\Hello\TestCase;./vendor/bin/phpunitを再実行します。TypeErrorになりました。これで$subject->to(1)は防げているということがわかります。PHPUnitでは「メソッド呼び出しが発生したらTypeErrorが発生する」ということをテストすることもできるのですが、型宣言を設定したあらゆる箇所に「(文字列以外の型)を渡したらTypeErrorが発生する」ということをテストしても仕方ないので、これは消してしまって良いでしょう。いうことで、$subject->to(true)や$subject->to(1.0)などのテストは全部消してしまって構いません。最終的にこうなりました。}}PhanをインストールしようPhanも強力な静的解析ツールのひとつです。Lerdorfが所属していたEtsy社で開発されていましたが、現在はPhanの開発コミュニティに移管されています。インストールにはいままでと同じようにcomposer-bin-pluginを利用します。--initで設定ファイルを生成することができます。.phan/config.phpが生成されるので、これもGitでコミットしておきましょう。ここまできたら手慣れたものですね。間違いなければ、たぶん何も警告は出ないと思います。Phanは前に紹介したPHPStan・Psalmと何が違うのでしょうか。三種類もインストールしたのでしょうか。細かいことを言うと解析の方式が違うというのがあるのですが、正直なところ、こんな小さな規模のパッケージでは、できることは概ね一緒です。極端なことを言うと、どれか一種類だけを入れても用は足ります。この一連の記事は「慎重すぎる」ことが旨ですので、石橋を叩いて渡るがごとく、三種類を全部使っていきます。Psalm)はどれも精力的に開発されており、毎週のように新しいバージョンがリリースされています。細部では三種類それぞれ異なる方式で検査しているので、どれか一つでしか検出されない問題というのもあります。品質を高く保とうと思えば、一から書きはじめるライブラリでは三種類の静的解析の全部で解析をするというのは別段法外にコストが高いということもないでしょう。実装の行数が増えていって簡単に解決できない問題を指摘されたり無益な項目ばかり指摘されるなと思ったらツールを減らしていくという判断もアリです。ここで注意してほしいのは「三種類全部入れる」というのは新規で書き始めるプロジェクトの話であって、既存のプロジェクトで静的解析で指摘される項目を全部潰すというのは気合を入れて直していかないと、かなり大変です。三種類のツール全部で通すなら法外にコストが掛かることになりかねません。過ぎたるは及ばざるが如しと言います。静的解析に適合するように修正したつもりが、バグを埋め込んでしまうということになりかねません。静的解析というものは「コードを実行してないけど危なそうだよ」という技術であって、ユニットテストのような手段であっても「実行したコードが意図した通りに動いている」という事実の方が常に優先されます。(ただしテストコードが意図を表現できず間違っているということはありえます)いろんな時間にあいさつしよう!いままで実装してきたのはHelloと言うしか能のない単細胞野郎です。実際には日本語には時間帯ごとに豊富な挨拶表現があります。時間帯ごとに違った挨拶ができるようにプログラミングしていきましょう。まとめ以下のツールについて紹介しました。