PHPDocとは、クラスや関数などのブロックに記述できるDocComment内に記述する書式の通称です。この書式の情報源として時折PSR-5が参照されることがあるので簡単に状況をまとめます。
TL;DR
- PSR-5の標準化ステータスは昨年10月にABANDONED (放棄・議論停滞)になりました
- PHPDocを型注釈として利用する各処理系の実装にはばらつきがあり、PSR-5とは相違点がある
- PhpStormは現在のところ(2018.1 EAP)PSR-5と互換性がないのでチーム開発では注意が必要です
この記事は2018年3月11日現在の進行中の話題を扱ってるので、遠からず時代遅れになるおそれがあります。
PSRって何?
PHP-FIG (PHP Framework Interop Group、PHPフレームワーク相互運用グループ)が策定する、PHPの共通仕様です。
PSR (PHP Standards Recommendations、PHP標準勧告)は若干権威を帯びた言葉ですが、「PHP開発者全員が知っておかなければモダンなPHPを書けない」といった性質のものではありません。策定プロセスはPHP本体(The PHP Group)とは直接関係なく、飽くまでPHPを使って構築されたフレームワークやCMSなどの開発者間での合意に過ぎません。
ただし、PSR-7(HTTP Message Interface)をはじめとする有用なクラスの仕様が定義されてますので、もし自分で同じようなクラスの車輪の再発明をするならばPSRで定義されたインターフェイスに準拠することも選択肢のひとつです。
PSR-5の状態
私はWEB+DB PRESS Vol.87で、PHPDocを紹介しました。これは8ページの連載記事ですが、2018年現在においてもPHPDocについて、おそらく最も網羅的にまとめたものです。
この記事において、私はPSR-5について以下のように言及しました。
残念ながらこの状況は改善せず、断続的な提案はあるもののコーディネイターの不在により議論はまとまらず、2015年末頃を最後に一切の作業が停滞しました。その後2017年10月頃にABANDONEDのステータスとして再分類されました。誰かがコーディネイターとして名乗り出て議論を再開させないと話が進まない状況です。
デファクトにおける仕様
phpDocumentorの型表記 (基本)
型の定義 — phpDocumentorに定義があります。特に配列の書式については以下の種類があると説明されます。
- 内容の型の記述なし
@return array
- 内容の単一型を記述
@return int[]
- 内容の複数型を記述
@return (int|string)[]
そのほか、2.と普通の複合型(int|string
)を組み合せてint[]|string[]
と書くこともできます。(これは3.とは別です)
Note
多くのIDEは、おそらくまだこの表記をサポートしません。
この記述の通り、現在でも3.の形式をサポートしないツールはいくつかあります。それ以外の形式はおそらく事実上の標準としてさまざまなツールでサポートされてます。
Annotating Types via PHP Doc Comments - Documentation
PSR-5の型表記
基本的にはPHPDoc形式の型表記を踏襲しつつ、コレクションのジェネリクスをサポートしました。しかし、開発が停滞した時期の都合でiterable
や?
(nullable)が含まれません。
/**
* @return \ArrayObject<int, \DateTimeInterface>
*/
function hoge() {
return new ArrayObject([
new DateTime("2003-04-07"),
new DateTime("2008-04-01"),
new DateTime("2112-09-03"),
]);
}
/**
* @return \ArrayObject|\DateTimeInterface[]
*/
function hoge2() {
return new ArrayObject([
new DateTime("2003-04-07"),
new DateTime("2008-04-01"),
new DateTime("2112-09-03"),
]);
}
この形式はphpDocumentor/TypeResolverが2017年12月末にリリースされた0.5.0でようやく対応したほか、PHPStan、Phanなどがサポートします。その一方、PhpStormこの表記を2018.1 EAP(Early Access Program、次期リリースの先行評価版)においても解釈しません。
つまり、PhpStormとの互換性を保つためには、PSR-5形式のジェネリクス記法で書くことを諦める(あるいは冗長に書く…)しかありません。PhpStormを使ってるみなさんはPHPDoc PSR-5 collection type hints formatting : WI-31960に投票してください。
Phanの型表記
Phan独自のタグはAnnotating Your Source Code · phan/phan Wikiで定義されます。PhpDocumentorやPSR-5形式の型表記は基本的に受理されます。
強烈な特徴は、つい最近2018年2月にリリースされたPhan 0.11.2で導入されたarray shapes
記法です。これは、配列のキーごとに型を定義できるようになった新たな配列記法です。
この記法は以下のようなパターンに対応できます。
list($id, $name, $prices) = hoge();
/**
* @return array{0:int,1:string,2:Money[]}
*/
function hoge()
{
return [1, 'hoge', [new Money(120), new Money(110)]];
}
また、当然連想配列に対しても型検査ができます。
$vocaloids = fuga();
foreach ($vocaloids as $v) {
printItem($v['item']);
}
/**
* @return array{name:string,age:int,item:?Item}
*/
function fuga()
{
return [
[
'name' => "初音ミク",
'age' => 16,
'item' => new Item("ネギ"),
],
[
'name' => "重音ミク",
'age' => 31,
'item' => new Item("フランスパン"),
],
];
}
こうなるとPhpStormなどのツールとの互換性が破滅するので、@phan-var
, @phan-param
, @phan-return
, @phan-property
, @phan-method
などの新しいタグが新設されました。array shapes
記法を利用する場合は複数の記法を両立することができます。…………おう。
/**
* @return array[]
* @phan-return array{name:string,age:int,item:?Item}
*/
function fuga()
{
PHPStanの型表記
PHPStanについては昨日PHPerKaigi 2018での@Hirakuの発表で知りました。で、実装を読んでみて驚いたのですが、PhpDocumentorとPSR-5の型表記に対応してるだけでなく&
記法でIntersectionTypeを実装してます。
型の話をしようと思ったら頭が痛くなるので、TypeScriptについて言及された、こちらの高等な型 | TypeScript 日本語ハンドブック | js STUDIOを読んでいただけると雰囲気掴める気がします。要は|
(または)の逆で&
(かつ)ってだけなのですが。
開発者本人が書いた記事: Union Types vs. Intersection Types – Ondřej Mirtes – Medium
たぶん以下のような型を書いて、引数の型チェックができるはずです。
/**
* @param Countable&Iterator $xs
*/
function hoge($xs)
{
これも強力でべんりな機能ではあるのですが、いつものようにPhpStormと互換性がありません。
Someone has to drive the innovation 😊 If I had to make a choice of sacrificing either PhpStorm or PHPStan, I'd sacrifice PhpStorm 😊 So the fact that the code is understood by PHPStan is more important to me.
いいぞもっとやれ。例によってPhpStormを急かしたければSupport for intersection types : WI-39419に投票してください。
PSR-5への個人的な不満
機能として欲しいものはいくつかあるのですが、PhpDocumentorの仕様にはあるタグ@property-read
と@property-write
を返してほしいです……。そもそも現在のプロポーザルでは型については“Appendix A. Types”(付録)なので、勧告の中での位置付けがさっぱりわからない。
結局どうなの
この記事の初稿の段階では「PSR-5全然実装されてないしだめだろ」みたいな論調で書こうと思ってたのですが、調べてみたらPhpStorm以外では結構実装されちゃってる感じでした。2016年11月あたりにPhan静的解析がもたらす大PHP型検査時代を書いたときにはPSR-5形式の型表記はサポートされてるツールが全然なくて絵に描いた餅だったのですが、気がついたらPHPStanやらphpDocumentor/TypeResolverが対応してくれてたので、あとはPhpStormだけが対応してくれればPSR-5の型が実用できるのでは、みたいな状況ではあります。
とは言ってもまだ足りない感じがする上にPHPStanが導入してIntersectionType(交差型)を見せられてしまっては、機能としてはともかく、書式の標準化はがんばってほしいところではあります。
JetBrainsがスポンサーになってPhpStormの関係者がしゃしゃり出てコーディネートしてくれないと話が進みそうにないんですが……。PhanもPHPStanもコア開発者が一人で猛然と開発していくタイプっぽいので、議論をまとめるとかそんな感じではなさげ。うーん。
ちなみにPSR-5が割り当てられたABANDONEDは、PHP版ジョークRFCとして名高い (?) PSR-8 Hug (日本語訳)と同じ分類です。PHPDoc=Haggable
おまけ: 資料
- PHPStan
- Phan
- phpDocumentor/TypeResolver
- PSR-5 (提案)
- Scrutinizer CI
-
|
と&
の話