ジェネレータ関数のDocコメントのreturnタグは何と書けばよいか

PHP 5.5で導入されたジェネレータ、便利です。

ジェネレータを使ったコードをいくつか書いたのですが、ふと気になることができました。
それは、ジェネレータ関数の「返値の型」は何なのか、ということです。

たとえば、

```php
function stringGenerator()
{
  yield 'string';
}
```

というジェネレータ関数を作ったとします。
ジェネレータ関数も関数なので、Docコメントで関数の説明を書きましょう。

```php
/**
 * 文字列をyieldするジェネレータ
 *
 * @return 型 返値の説明
 */
function stringGenerator()
{
  yield 'string';
}
```

ここで疑問が生じます。
`@return`タグの「型」には何と書くのがよいのでしょうか。
`string`？ それとも、`\Generator`？

#調査

##過去の自分のコードを見返してみる
試しに私が過去に書いたコードのジェネレータ関数のDocコメントを見返してみると、
`@return \Generator 返値の説明（※文字列をyieldする）`
という記述と
`@return string 返値の説明（※ジェネレータなので必ずforeach等で受けること）`
という記述と両方あって、統一されていませんでした。
これまであまり深く考えたことがなかったので仕方ありませんが、これではいけません。統一した書式を決めなければ。

##PHPのマニュアルを調べる

[PHPマニュアルの「ジェネレータとは」のページの「Generator オブジェクト」の節][php-generator-object]によれば、

>ジェネレータ関数を最初に呼んだときには、内部クラス Generator のオブジェクトを返します。 

とのことなので、ジェネレータ関数の「返値の型」は`\Generator`クラスのオブジェクトであり、Docコメントの`@return`タグは
`@return \Generator 返値の説明`
とするのが正解な気がします。

しかし、`yield`した値の型が分からないのは何とも不便です。
`@return string 返値の説明`
と書きたくなります。ですが、これだと`return`文で文字列値を返す普通の関数と見分けがつきません。

##phpDocumentorのマニュアルを調べる
ジェネレータ関数の「返値の型」が`\Generator`オブジェクトであるとして、`yield`される値をそのオブジェクトの要素と考えればどうでしょう。

配列であれば、型を`array`で表すこともできますし、要素が文字列の配列なら`string[]`、整数の配列なら`int[]`のように、`要素の型[]`の形で表すこともできます。

同じようにして、`\Generator`オブジェクトと、`yield`される値の型を同時に表すことはできないでしょうか。

そこで、phpDocumentorのマニュアルには何と書いてあるだろうかと、[phpDocumentorマニュアルの「Types」のページ][phpdocumentor-types-old]を見てみました。しかし、それらしい記述は見つかりませんでした。

##PSRを調べる
それではPHPのコーディング規約であるPSRに何かないかと見てみると、まだ**草案（Draft）**ではありますが、**PSR-5**でPHPDocの書き方を定めているとのこと。GitHubにある[「PSR-5: PHPDoc」の草案][psr-5]を見てみると、使えそうなものが見つかりました。

それが、「[Collections][psr-5-collections]」です。

たとえば、`\ArrayObject`というクラスのオブジェクトがあり、それが文字列型の要素を持っているとします。これの「型」を、Collectionsでは`\ArrayObject<string>`と書くようです。

これを応用すれば、文字列値を`yield`するジェネレータ関数の「返値の型」は、文字列型の要素を持つ`\Generator`オブジェクトであると考えて、`\Generator<string>`と表せそうです。つまり、Docコメントの`@return`タグは、
`@return \Generator<string> 返値の説明`
と書けそうです。

#結論

ジェネレータ関数のDocコメントの`@return`タグは、
`@return \Generator<yieldする値の型> 返値の説明`
のように書くことにします。

#補足

- 上記PSR-5の「Collections」では、オブジェクトの要素のキーの型を指定する方法も示されていました。たとえば、整数値のキーを持つ文字列値を要素に持つ`\ArrayObject`オブジェクトは`\ArrayObject<int, string>`のように表すようです。これを用いれば、`yield $key => $value;`というジェネレータ関数のDocコメントの`@return`タグは、`@return \Generator<$keyの型, $valueの型> 説明`のように書けそうです。
- この記事を執筆する（2016年4月8日）よりも前の2013年～2015年に、[phpDocumentorのGitHubリポジトリにIssueが立てられ][phpdocumentor-fig-standards-issue-5]既に同様の議論が行われていたようです。こちらでも、本稿と同様`@return \Generator`か`@return \Generator<string>`のように表すのがよいだろうという話のようでした。中には`Generator::current()`の返値の型`V`、`Generator::key()`の返値の型`K`、`Generator::send()`の返値の型`S`、`Generator::getReturn()`の返値の型`R`を使って`Generator<V, K, S, R>`と表すべきだとの意見もありましたが、さすがにそれは面倒臭いなという印象を受けました。また、`@return`タグの代わりに`@yield`タグを新設すべきだという意見も出ていましたが流れてしまったようです。なかなか難しい問題ですね。
- ~~PSR-5がまだ「Draft」（草案）であることには十分注意する必要があると思います。~~  
  ~~2017年10月に、PSR-5の策定状況が「Draft」から「Abandoned」（放棄）に変更されました。~~  
  2018年9月26日に、PSR-5は再び「**Draft**」になりました。また、PSR-5は分割され、PSR-5とPSR-19の2つのPSRになりました。分割後のPSR-5はPHPDocの書式を規定し、PSR-19はタグの一覧を規定します。

# 参考文献

- [『PHP: ジェネレータとは - Manual』][php-generator]
- [『Types — phpDocumentor』][phpdocumentor-types]  
  本記事執筆時は https://www.phpdoc.org/docs/latest/guides/types.html を参照していたのですが、2018年9月2日現在では https://docs.phpdoc.org/guides/types.html にリダイレクトされるようです。書かれている内容が記事執筆時とは異なるかもしれません。
- [PHP-FIG『PHP Standards Recommendations - PHP-FIG』][psr]  
  PSRとその策定状況の一覧
- [PHP-FIG『PSR-5: PHPDoc』][psr-5]  
  PHP-FIGのGitHubリポジトリにあるPSR-5の草稿。なおPHP-FIGのサイトのPSR一覧表では、こちらではなく[phpDocumentorによるフォーク][phpdocumentor-psr-5]の方にリンクされているようです。これはphpDocumentorのフォークを参照した方が良いということでしょうか。ちなみに本記事を書いた時にはphpDocumentorのフォークの方を見て執筆し、その後本家PHP-FIGのGitHubリポジトリの方にリンクを張り直しました。当時は両者とも内容にほぼ差は無かったのですが、2018年9月2日現在ではかなり差が出ています。phpDocumentor版は最終更新が2016年2月（2年前）なのに対し、PHP-FIG版は今年2018年7月に入って大きな変更が加えられています。**2018年9月にはPSR-5とPSR-19とに分割されました。**
- [PHP-FIG『PSR-19: PHPDoc tags』][psr-19]
- [mvriel・他『Yield? · Issue #5 · phpDocumentor/fig-standards · GitHub』] [phpdocumentor-fig-standards-issue-5]

# 関連記事

- [tadasan『2018年のPHPDoc事情とPSR-5』][tadasan]  
  本記事とは直接関係ありませんが、PHPDocの状況についてまとめてくださっています（2018年3月現在の情報）。この記事でPSR-5が放棄されたのを知りました。

[php-generator]: https://secure.php.net/manual/ja/language.generators.overview.php
[php-generator-object]: https://secure.php.net/manual/ja/language.generators.overview.php#language.generators.object
[phpdocumentor-fig-standards-issue-5]: https://github.com/phpDocumentor/fig-standards/issues/5
[phpdocumentor-psr-5]: https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md
[phpdocumentor-types]: https://docs.phpdoc.org/guides/types.html
[phpdocumentor-types-old]: https://www.phpdoc.org/docs/latest/guides/types.html
[psr]: https://www.php-fig.org/psr/
[psr-5]: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md
[psr-5-collections]: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md#collections
[psr-19]: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc-tags.md
[tadasan]: https://qiita.com/tadsan/items/72b02339d12120ca37d7