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 GroupPHPフレームワーク相互運用グループ)が策定する、PHPの共通仕様です。

PSR (PHP Standards RecommendationsPHP標準勧告)は若干権威を帯びた言葉ですが、「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について以下のように言及しました。

スクリーンショット 2018-03-11 午後4.09.59.png

残念ながらこの状況は改善せず、断続的な提案はあるもののコーディネイターの不在により議論はまとまらず、2015年末頃を最後に一切の作業が停滞しました。その後2017年10月頃にABANDONEDのステータスとして再分類されました。誰かがコーディネイターとして名乗り出て議論を再開させないと話が進まない状況です。

デファクトにおける仕様

phpDocumentorの型表記 (基本)

型の定義 — phpDocumentorに定義があります。特に配列の書式については以下の種類があると説明されます。

  1. 内容の型の記述なし @return array
  2. 内容の単一型を記述 @return int[]
  3. 内容の複数型を記述 @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

おまけ: 資料

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.