機能テストはいいぞ!

ふと、機能テストの良さについて語りたくなったので投稿。

単体テストより先に機能テストを書こう!

「テストを書く」というと単体テスト(ユニットテスト)を想像しがちですが、WEBシステムなら機能テスト(HTTPテスト)を先に書くことがおすすめです!

先に用語を整理しておきましょう。
まず、単体テストというのは(基本的に)メソッドや関数が想定通りに動いているかを確認するものです。
次に、機能テストというのは画面に表示されているものが想定通りに表示されているかを確認するものです。1

なぜ機能テストを先に書くといいの?

時間は有限なので、重要なテストから書きたいためです。 もちろん機能テストと単体テストを両方とも書けるといいですが、色々な都合で片方のテストしか書く時間がとれない場合、機能テストを書くことをおすすめします。 なぜなら、機能テストはユーザへの価値提供に直結するテストだからです。

また、機能テストのほうが直感的に書きやすいです。

  1. ストーリーの仕様をそのままテストにすれば良い

    単体テストはメソッド単位の粒度でテストを書くため、先にある程度のクラス設計が必要になります。一方で機能テストはページ単位の粒度でテストを書くため、クラス設計を待たずに書くことができます。

  2. テクニックが必要とされない

    単体テストではテストをしやすくするためのテクニック2が必要になりますが、機能テストではあまり必要になりません。言語の基本構文さえ身に付いていれば書き始めることができます。

機能テストを書くには?

機能テストを書くには、テストライブラリを使用すると良いです。
PHP界隈ではBehatをよく耳にします。が、私は使ったことがありません。
私はよくCodeceptionを使用しています。多くのフレームワークに対応しているのが特徴です。
また、Laravelではテストの機能を内包しており、追加ライブラリなしに機能テストを書くことができます。

機能テストのサンプル

実際にサンプルがないとわかりづらいですよね。
ここからは、LaravelでCodeceptionを利用した場合のサンプルを載せます。

$this->assertEquals(2, 1 + 1); のような何も参考にならない例ではなく、実際のシステムを想定した例を出していきます。

例えば、ブログシステムを考えてみましょう。
このブログシステムのトップページの要件は以下になります。

  • 記事がない場合は「まだ記事がありません」と表示される
  • 新着記事3つが掲載される
  • 非公開フラグの記事は表示されない

ひとつひとつをテストに落とし込んでみましょう。

最初のテスト

まず、トップページが表示されるテストを書きたいと思います。
これは暗黙的な要件ですが、ひとつのテストとして作成しておくと、バグが発生したときに対応しやすくなります。

<?php

public function トップページが表示される(FunctionalTester $I)
{
    $I->amOnPage('/');
    $I->seeResponseCodeIs(HttpCode::OK);
}

これは、「トップページにアクセスするとHTTPステータスコードが200番で返ってくる」というテストです。
ルーティングでミスっていれば404で返り、サーバ内でエラーがあれば500で返るため、バグの切り分けが容易になります。

ちょっとテクニック寄りなテストなのであまり機能テストっぽくありませんね。
次から機能テストらしさを出していきます!

記事がない場合は「まだ記事がありません」と表示される

先にコードを示します。

<?php

public function 記事がない場合は「まだ記事がありません」と表示される(FunctionalTester $I)
{
    $I->amOnPage('/');
    $I->see('まだ記事がありません');
}

どうでしょうか。わかりやすいと思いませんか?
$-> などの記号を抜くと、以下のようになります。

I am on page /  
I see まだ記事がありません

完璧な英語ではないですが、意味が完全にわかる形で読めますね!
これこそが機能テストの真価です!

新着記事3つが掲載される

このケースの場合、記事を事前に用意しておく必要があります。

<?php

public function 新着記事3つが掲載される(FunctionalTester $I)
{
    $newers = $I->haveMultiple(Article::class, 3, ['published_at' => '2001-01-01 00:00:00']);
    $older = $I->have(Article::class, ['published_at' => '2000-01-01 00:00:00']);

    $I->amOnPage('/');

    foreach($newers as $newer)  {
        $I->see($newer->title);
    }
    $I->dontSee($older->title);
}

havehaveMultiple メソッドで記事を生成しています。
また、このテストでは dontSee メソッドを用いて、4つ目の記事が表示されていないことをテストしました。

非公開フラグの記事は表示されない

このテストケースは今までの内容で記述できますね。

<?php

public function 非公開フラグの記事は表示されない(FunctionalTester $I)
{
    $article= $I->have(Article::class, ['publish_status' => PublishStatus::UNPUBLISH]);
    $I->amOnPage('/');
    $I->dontSee($article->title);
}

おわりに

  • 単体テストより先に機能テストを書こう!
  • 機能テストを書くにはテストライブラリを使おう!
  • 自然な表現でテストを書けるぞ!

あまり機能テストをガシガシ書いている人に出会ったことがないので、少しでも広まればいいと思います。


  1. 機能テストではJavaScriptの動作を確認することができません。JavaScriptの動作を確認したい場合は、ブラウザのエミュレータを使用した受入テストを書く必要があります。

  2. DIなど

dockerに入門してみた

docker、名前は聞いたことあるものの、全然ノータッチだったので、勉強してみた。
いつも「dockerとvagrantの違い」あたりを読んで挫折し始めるので、そこらへんはスキップします。
dockerやインフラ初心者にとっては、そこってホントどうでもいいところなんですよね・・・(少なくとも初心者である時点では)
ということで、手を動かすことメインで入門してみました。

参考サイト

www.ogis-ri.co.jp

環境

windows10Pro (10Sからの変更)

dockerインストール

適当にインストーラ落として入れればok

docker ps

さっそくエラーが出る

PS C:\Users\dormi> docker ps
error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.37/containers/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.

dockerが立ち上がってない? Win+Qでアプリ検索してdocker立ち上げ。

PS C:\Users\dormi> docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

無事にでたー!

docker run hello-world

PS C:\Users\dormi> docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:97ce6fa4b6cdc0790cda65fe7290b74cfebd9fa0c9b8c38e979330d547d22ce1
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
  https://docs.docker.com/engine/userguide/

まずlocalのイメージを探して、なければダウンロードするんですね。 というか、番号付きリストのところに何が起こったか書いてありますね。やさしい。

docker pull

PS C:\Users\dormi> docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
ff3a5c916c92: Pull complete
Digest: sha256:7b848083f93822dd21b0a2f14a110bd99f6efb4b838d499df6d04a49d0debf8b
Status: Downloaded newer image for alpine:latest

run はダウンロードして実行するけど、 pull は落とすだけって感じ?

docker images

PS C:\Users\dormi> docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              3fd9065eaf02        2 months ago        4.15MB
hello-world         latest              f2a91732366c        3 months ago        1.85kB

ダウンロードしたイメージが見れるっぽい。

docker run

PS C:\Users\dormi> docker run alpine echo "hello from alpine"
hello from alpine

コマンドやってることは分かったけど、補完依存症の僕にとっては、イメージ名は補完してほしいな感。
fishとか使ったらいい感じに補完してくれたりしないのかな。

docker run -it

PS C:\Users\dormi> docker run -it alpine bin/sh
/ # ls
bin    dev    etc    home   lib    media  mnt    proc   root   run    sbin   srv    sys    tmp    usr    var

なるほど。 -it でイメージに入れるんですね。 -i-t が何を指してるかは、これからわかるのかな?
(なんとなく想像はつくけど。)

docker ps(2回目)

PS C:\Users\dormi> docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
209aff4c011b        alpine              "bin/sh"            5 minutes ago       Up 5 minutes                            agitated_sinoussi

起動中のイメージが表示されるのね

docker stop

PS C:\Users\dormi> docker stop 209aff4c011b
209aff4c011b

イメージを停止させるのかな?
ちょっと時間かかる

docker start

PS C:\Users\dormi> docker start 209aff4c011b
209aff4c011b

なるほど。 stop したイメージを再開させるのか。

docker attach

PS C:\Users\dormi> docker attach 209aff4c011b
/ #

これで stop したイメージにまた入れるのね。

docker rm

PS C:\Users\dormi> docker rm 209aff4c011b
Error response from daemon: You cannot remove a running container 209aff4c011b8f7ba6f469ef17540c599125ccad6aff6cfb1a9b2d907792ed7a. Stop the container before attempting removal or force remove

stop しないまま実行しようとすると怒られる

PS C:\Users\dormi> docker stop 209aff4c011b
209aff4c011b
PS C:\Users\dormi> docker rm 209aff4c011b
209aff4c011b

いけた。

PS C:\Users\dormi> docker start 209aff4c011b
Error response from daemon: No such container: 209aff4c011b
Error: failed to start containers: 209aff4c011b

消すともう再開できないらしい。

サーバーを動かす

PS C:\Users\dormi> docker run --name static-site -e AUTHOR="Docker" -d -p 80:80 seqvence/static-site
Unable to find image 'seqvence/static-site:latest' locally
latest: Pulling from seqvence/static-site
fdd5d7827f33: Pull complete
a3ed95caeb02: Pull complete
716f7a5f3082: Pull complete
7b10f03a0309: Pull complete
aff3ab7e9c39: Pull complete
Digest: sha256:41b286105f913fb7a5fbdce28d48bc80f1c77e3c4ce1b8280f28129ae0e94e9e
Status: Downloaded newer image for seqvence/static-site:latest
ff91ee73c66b3b175f148a7d0e2c0bda8f24f9c9a26467df1d2a6c6d4d9034ec

引数多くて「ウっ」てなる。
--name は別にいらんのかなーとも思う。

サイトを表示するためにはデフォルトでバインドされるIPアドレスを調べないといけないらしいが・・・

PS C:\Users\dormi> docker-machine ip default
Docker machine "default" does not exist. Use "docker-machine ls" to list machines. Use "docker-machine create" to add a new one.

なんかエラー出る・・・ とりあえず http://localhost でつながったけど・・・・微妙ですね。
ここの設定をどうやって出せるかは知りたいところ。

ネット徘徊してたらこれでIPアドレスわかるらしいが・・・

PS C:\Users\dormi> docker inspect -f "{{ .NetworkSettings.IPAddress }}" ff91ee73c66b
172.17.0.2

なんか違いそう。 これ内部のIPアドレスよね。

色々調べた結果、Dockerへの接続を知りたいだけなので、

PS C:\Users\dormi> ipconfig

で良かったのだった・・・

PHP-BLT #8 でPHPDocについて発表しました。

PHP-BLTにいってきました

8/8にあったPHP-BLT #8 で「PHPDocのおさらい」というタイトルで発表しました。

内容としては「PHPDocで関数とかの仕様書けるよ!」という当たり前すぎる話を5分に引き伸ばした感じです。 ただこの話は、自分の中で悶々と溜めてたことなので、話せてよかったなーと思います。

今回は初めてのLTということで、事前にスライド見ながら練習とかしてみたんですけど、やっぱり5分は短いですね。
色々話したかったけど時間で話せないこともあったので、ここで発散しておきます。

PHPDocをなぜ書くのか

今回の発表では、「コードレベルの仕様を書きたいから」というのを理由にしてますし、私自身もそれが一番の理由だと思っています。

ですが、「静的解析したいから」という理由の人が一定数います。

もちろん私もPhpStorm大好き人間なので静的解析には大変にお世話になっていますし、静的解析のためのPHPDocも書くことはあります。( @var とか)
ですが、それはあくまで副次的な利点であり、本質は違うんじゃないかなと思います。

やはりPHPDocの源流はJavaDocだと思いっています。 Javaは型ガッチリな言語なので、JavaDocの発展に静的解析はあまり関係していないと思うんですよね。(総称型とかは置いといて)
それと同じように、PHPDocの本来の目的も、静的解析ではなくもっと別のところにあるのかなと思います。

今回はそれを「仕様を書きたいから」というところに着地させています。

仕様は命名からわかるべき

「仕様を書かなくてもわかるようなクラス・メソッド名や関数名にするべき」という意見をよくききます。
リーダブルコードにも書いてある内容ですよね。

もちろんそれはそうなのですが、理想と現実は違うのかなと感じています。
というのも、

  • そんなに英語できる人が少ない(語彙や前置詞の使い方など)
  • 2,3ワードでほんとに仕様を説明できるの?

みたいな問題があるのかなと。

あとは、フレームワークの制約上難しい場合もありますよね。
例えばYii1系だと、 beforeAction というメソッドがあり、名前のとおり各アクションを実行する前に実行されます。
このメソッドを利用する時に、このメソッドの仕様を命名で解決できるかというと、無理ですよね。(どのタイミングで実行されるかは明白だけど、何をするのかはわからない)

もちろん命名が不要なわけではないです。
概要を命名で説明して、細かい仕様をPHPDocで説明するくらいの温度感がいいのかなと思います。

PHP-BLT楽しかった!

ちなみに私以外で発表していた人は「よく勉強会やカンファレンスで喋ってるあの人」みたいな人ばっかりでした。
そして内容も難しい話ばっかりでした。みんな凄いなー。
でも知らないことを知ったり、自分と違う環境の人と話すことはとても楽しいですよね。
また次も参加したいなー。

今回は体調不良だったので、次回は体調良好な状態でいきたい!

laravel5.3 CSVダウンロードを実装する

先日、CSVダウンロードで盛大にコケまくったので、メモ。

わりとコードが長くなってしまったので、fopenが失敗した場合や文字コードの変換については書いていません。

経過なんてどうでもいい!結果だけくれ!という方は下から読むといいと思います。

CSVダウンロードの簡単な実装

頑張って手作りするとこんな感じ。

<?php
    public function downloadCSV()
    {
        $csv = [
            ['id', 'name', 'age'],
            ['1', 'tanaka', '20'],
        ];
        
        $csvContent = '';
        foreach ($csv as $line) {
            $csvContent .= '"' . implode(',', $line) . '"';
            $csvContent .= PHP_EOL;
        }
        
        return response(
            $csvContent,
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="users.csv"',
            ]
        );
    }

初めて作ってみるとこんな感じになりますよね。
ちなみにこの実装は非常によろしくないです。
CSVのエスケープ処理が充分に考えられていません。(ダブルクォーテーションが値に入ってたら崩れます)

fputcsvを使う

自分でCSVのエスケープを書くのは面倒なので、 fputcsv 関数を使用するように変更します。
fputcsvはfopenの返り値に対して使用できるので、いちど適当にファイルに吐いてから取得するようにします。

<?php
    public function downloadCSV()
    {
        $csv = [
            ['id', 'name', 'age'],
            ['1', 'tanaka', '20'],
        ];
        
        $stream = fopen('/temp/users.csv', 'w');
        foreach ($csv as $line) {
            fputcsv($stream, $line);
        }
        fclose($stream);

        rewind($stream);
        $csvContent = stream_get_contents($stream);

        return response(
            $csvContent,
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="users.csv"',
            ]
        );
    }

これで正確なCSVを出力できるようになりました。
ですが、データが多いとファイルI/Oが頻繁に発生しそうです。

php://output を使う

いちどファイルに入れずに、直接出力してしまえば、ファイルI/Oは気にしなくて済みます。
ファイルのパスを php://output に変更しましょう。

<?php
    public function downloadCSV()
    {
        $csv = [
            ['id', 'name', 'age'],
            ['1', 'tanaka', '20'],
        ];
        
        $stream = fopen('php://output', 'w');
        foreach ($csv as $line) {
            fputcsv($stream, $line);
        }
        fclose($stream);

        return response(
            '',
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="users.csv"',
            ]
        );
    }

これでファイルI/Oを気にしなくてよくなりました!
ですが、データが多いとヘッダーが無視され、ブラウザ上に出力されてしまいます!
理由はヘッダーを送る前にデータを送っているからのようです。
おそらく、ブラウザかサーバー(apacheとか)で「こんだけ待ってもヘッダー来ないから、もうデフォルトのヘッダーだと思って出力しちゃえ!」ってなってるんだと思います。

StreamedResponseを使う

先にヘッダーを送ってしまえばこの問題は解決しそうです。
response 関数は第一引数に出力内容を文字列で渡しますが、 StreamedResponse クラスは出力内容をコールバックで渡すことができます。

<?php
    use Symfony\Component\HttpFoundation\StreamedResponse;

    public function downloadCSV()
    {
        return  new StreamedResponse(
            function () {
                $csv = [
                    ['id', 'name', 'age'],
                    ['1', 'tanaka', '20'],
                ];

                $stream = fopen('php://output', 'w');
                foreach ($csv as $line) {
                    fputcsv($stream, $line);
                }
                fclose($stream);
            },
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="users.csv"',
            ]
        );
    }

データベースの内容を出力する

だいたいのケースにおいて、CSV出力したいものはあらかじめ定義した配列ではなく、データベースの中のデータではないでしょうか。

<?php
    use Symfony\Component\HttpFoundation\StreamedResponse;
    use App\User;

    public function downloadCSV()
    {
        return  new StreamedResponse(
            function () {
                $csv = User::all(['id', 'name', 'age'])->toArray();

                $stream = fopen('php://output', 'w');
                foreach ($csv as $line) {
                    fputcsv($stream, $line);
                }
                fclose($stream);
            },
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="users.csv"',
            ]
        );
    }

Eloquentは結果を Collection クラスで返すので、忘れずに配列に変換しましょう。
ただ、データが多いとメモリが枯渇してしまいます。

chunkを使う

一度にすべてのデータを取得するのではなく、データを分割して取得し、その都度、出力すればよさそうです。

<?php
    use Symfony\Component\HttpFoundation\StreamedResponse;
    use App\User;

    public function downloadCSV()
    {
        return  new StreamedResponse(
            function () {
                $stream = fopen('php://output', 'w');
                User::chunk(100, function ($users) use ($stream) {
                    foreach ($users as $user) {
                        fputcsv($stream, [$user->id, $user->name, $user->age]);
                    }
                });
                fclose($stream);
            },
            200,
            [
                'Content-Type' => 'text/csv',
                'Content-Disposition' => 'attachment; filename="users.csv"',
            ]
        );
    }

これで問題なさそうです。
CSVダウンロードは考えることが多くて大変ですね。

Laravel5.3 str_limitにご用心

laravel.com

Laravelのヘルパー関数って便利なものがいっぱいありますよね。

特に str_limit という関数が素敵に感じました。
文字列を指定した数値で切り詰める関数です。
ですが、日本語で使うときは要注意です。

例えば、12いちにー という文字列に str_limit を使用してみましょう。

長さ 理想 現実
1 1 1
2 12 12
3 12い 12
4 12いち 12い
5 12いちに 12い
6 12いちにー 12いち

どうやらマルチバイトの文字列でこけるようです。

なぜそのようなことが起こるか調べてみたところ、str_limitは文字でなく、文字で切り詰めるようになっていました。

<?php
    public static function limit($value, $limit = 100, $end = '...')
    {
        if (mb_strwidth($value, 'UTF-8') <= $limit) {
            return $value;
        }
        return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end;
    }

文字幅で切り詰めるケースは日本では無さそうなので、文字数で切り詰める関数を自作したほうがよさそうです。

こんな感じでしょうか。

<?php
    public static function str_limit($value, $limit = 100, $end = '...')
    {
        if (mb_strlen($value, 'UTF-8') <= $limit) {
            return $value;
        }
        return rtrim(mb_substr($value, 0, $limit, 'UTF-8')).$end;
    }

PSR-5 を和訳してみました

PSR-5を和訳してみました。 といっても、Google翻訳にかけただけです。 まだ修正はかける予定ですが、現状のものを公開しておきます。

PSR-5: PHPDoc

Table Of Contents

1. 前書き

このPSRの主な目的は、PHPDoc標準の完全かつ正式な定義を提供することです。 このPSRは、phpDocumentor 1.xに関連する事実上のPHPDoc標準である前身から逸脱して、PHP言語の新しい機能をサポートし、以前のバージョンの欠点に対処しました。

This document SHALL NOT:

  • PHPDocを介してアノテーションを実装するための標準を記述します。 それは現行の慣習に基づいて後続のPSRを作成することを可能にする汎用性を提供するが、 このトピックの詳細については、chapter 5.3を参照してください。
  • PHPDoc標準のアプリケーションに関するコーディング標準のベストプラクティスまたは推奨事項を記述します。 このドキュメントは、構文と意図の正式な仕様に限定されています。

2. この文書で使用されている表記規則

この文書のキーワード “必須"、 "必須ではない"、 "必須"、 "ありません"、 "しない"、 "しない"、 "推奨する"、 "するかもしれない"、 ” RFC2119に記述されているように解釈されること。

3. 定義

  • 「PHPDoc」は、「構造要素」の側面に関する情報を提供するドキュメンテーションのセクションです。

    PHPDocとDocBlockは別々の2つのエンティティであることに注意することが重要です。 DocBlockは、コメントの一種であるDocCommentとPHPDocエンティティの組み合わせです。 この仕様で説明されているような構文とタグなどのPHPDocエンティティです。

  • “Structural Element"は、DocBlockの前に置かれるプログラミングコンストラクトの集合です。 コレクションには、次の構文が含まれています。

    • file
    • require(_once)
    • include(_once)
    • class
    • interface
    • trait
    • function (including methods)
    • property
    • constant
    • variables, both local and global scope.

    「構造要素」の前にDocBlockを置くことが推奨されています(DocBlockは定義されており、それぞれの用途には使用されません)。 DocBlockを構造要素の前に置くのが一般的ですが、未定義の空行で区切ることもできます。

    Example:

  /** @var int $int This is a counter. */
  $int = 0;


  // there should be no docblock here
  $int++;

or

    /**
     * This class acts as an example on where to position a DocBlock.
     */
    class Foo
    {
        /** @var string|null $title contains a title for the Foo with a max. length of 24 characters */
        protected $title = null;


        /**
         * Sets a single-line title.
         *
         * @param string $title A text with a maximum of 24 characters.
         *
         * @return void
         */
        public function setTitle($title)
        {
            // there should be no docblock here
            $this->title = $title;
        }
    }

この標準の範囲を超えた使用の例は、foreach内の変数を明示的に文書化することです。 いくつかのIDEは、この情報を使用して自動補完機能を支援します。

この標準は foreachステートメントが「構造要素」ではなくコントロールフローステートメントとみなされるため、この特定のインスタンスをカバーしません。

  /** @var \Sqlite3 $sqlite */
  foreach($connections as $sqlite) {
      // there should be no docblock here
      $sqlite->open('/my/database/path');
      <...>
  }
  • “DocComment” is a special type of comment which MUST

    • 文字列 / **で始まり、その後に空白文字が続きます
    • * /で終わり、
    • その間に0行以上あります。

    DocCommentが複数の行にまたがる場合、すべての行はアスタリスク(*)で始まり、開始句の最初のアスタリスクと整列しなければならない(SHOULD)。

    Single line example:

  /** <...> */

Multiline example:

    /**
     * <...>
     */
  • 「DocBlock」は、単一の「PHPDoc」構造を含む「DocComment」であり、基本的なソース内表現を表します。

  • 「タグ」は、「構造要素」またはその構成要素に関するメタ情報の単一の部分である。

  • “Inline PHPDoc"は、 "Structural element"の代わりに "Tag"に関連する "PHPDoc"です。 これは、 "タグ"の記述部分を置き換えます。

  • 「タイプ」は、どのタイプのデータが要素に関連付けられているかを判断します。 これは、引数、定数、プロパティなどの正確な値を決定するときによく使用されます。

    タイプの詳細については、付録Aを参照してください。

  • 「セマンティックバージョン」とは、Semantic Versioning Specification 2.0.0に設定されている定義を指します。

  • 「FQSEN」は、Fully Qualified Structural Element Nameの略語です。 この表記法は、完全修飾クラス名を拡張し、クラス/インターフェース/特性メンバーを識別する表記法を追加し、FQCNの原則をインターフェース、特性、関数およびグローバル定数に再適用します。

    「構造要素」のタイプごとに、次の表記を使用できます:

    Namespace: \My\Space Function: \My\Space\myFunction() Constant: \My\Space\MY_CONSTANT Class: \My\Space\MyClass Interface: \My\Space\MyInterface Trait: \My\Space\MyTrait Method: \My\Space\MyClass::myMethod() Property: \My\Space\MyClass::$my_property Class Constant: \My\Space\MyClass::MY_CONSTANT

    FQSENには、以下のABNF定義があります。

        FQSEN    = fqnn / fqcn / constant / method / property  / function
        fqnn     = "\" [name] *("\" [name])
        fqcn     = fqnn "\" name
        constant = (fqnn "\" / fqcn "::") name
        method   = fqcn "::" name "()"
        property = fqcn "::$" name
        function = fqnn "\" name "()"
        name     = (ALPHA / "_") *(ALPHA / DIGIT / "_")
    

4. 基本原則

  • PHPDocは常に “DocComment"に含まれなければなりません。 これら2つの組み合わせを「DocBlock」と呼びます。

  • DocBlockは、 “構造要素"の直前になければならない(MUST)

    この原則の例外は、ファイルレベルのDocBlockをファイルの最初のDocBlockとしてPHPソースコードファイルの先頭に置かなければならないことです。

    構造要素がファイルレベルのDocBlockの直後に来るときのあいまいさを避けるため、その要素にはファイルレベルのDocBlockに加えて独自のDocBlockがなければなりません。

    有効なファイルレベルのDocBlockの例:

    ``` <?php /* * This is a file-level DocBlock /

    /* * This is a class DocBlock / class MyClass { } ```

    無効なファイルレベルのDocBlockの例

    <?php /** * This is a class DocBlock */ class MyClass { }

5. PHPDoc形式

PHPDoc形式には、以下のABNF定義があります:

PHPDoc             = [summary] [description] [tags]
inline-phpdoc      = "{" *SP PHPDoc *SP "}"
summary            = *CHAR ("." 1*CRLF / 2*CRLF)
description        = 1*(CHAR / inline-tag) 1*CRLF ; any amount of characters
                                                 ; with inline tags inside
tags               = *(tag 1*CRLF)
inline-tag         = "{" tag "}"
tag                = "@" tag-name [":" tag-specialization] [tag-details]
tag-name           = (ALPHA / "\") *(ALPHA / DIGIT / "\" / "-" / "_")
tag-specialization = 1*(ALPHA / DIGIT / "-")
tag-details        = *SP (SP tag-description / tag-signature / inline-phpdoc)
tag-description    = 1*(CHAR / CRLF)
tag-signature      = "(" *tag-argument ")"
tag-argument       = *SP 1*CHAR [","] *SP

使用例は第5.4章に含まれています。

5.1. Summary

要約は、目的を定義する “構造要素"の要約を含まなければならない。 サマリーが1行にまたがっていることが推奨されます。

要約はどちらかで終わらなければならない

  • フルストップ(。)、その後の改行
  • または2つの連続した改行が含まれます。

Descriptionが提供されている場合は、その前にSummaryが必要です。 そうでない場合、概要は要約の終わりに達するまで要約とみなされます。

サマリーは章のタイトルに匹敵するので、可能な限り小さな書式を使用すると有益です。 したがって、説明(次の章を参照)とは異なり、マークアップ言語をサポートするための推奨は行われません。 これをサポートするかどうかは、実装するアプリケーションに明示的に委ねられます。

5.2. Description

DescriptionはOPTIONALですが、このDocBlockが先行する「構造要素」には、要約だけで説明されているよりも多くの操作や複雑な操作が含まれている場合に含める必要があります。

説明を解析するアプリケーションは、このフィールドのMarkdownマークアップ言語をサポートするように推奨されています。 これにより、作成者が書式を提供し、コード例を明確に表現できるようになります。

Descriptionの一般的な使用方法は次のとおりです。(とりわけ):

  • この方法の概要に関する要約よりも詳細を提供する。
  • 入力または出力配列またはオブジェクトがどの子要素で構成されるかを指定する。
  • 「構造要素」を適用できる共通のユースケースまたはシナリオのセットを提供すること。

5.3. Tags

タグは、著者が後続の「構造要素」に関する簡潔なメタデータを提供する方法を提供します。 各タグは、新しい行から始まり、アットマーク(@)とタグ名の後に空白とメタデータ(説明を含む)またはインラインPHPDocが続きます。

メタデータが提供されている場合は、複数の行にまたがる可能性があり、厳密な形式に従う必要があります。 したがって、タグの種類によって決まるパラメータが提供されます。 タグのタイプは、その名前から派生することができます。

For example:

@param string $argument1 This is a parameter.

上記のタグは、名前( ‘param')とメタデータ( 'string $ argument1This is a parameter.')で構成され、メタデータは「タイプ」(「文字列」)、変数名 $ argument ')とdescription('This is a parameter.')。

タグの記述はMarkdownをフォーマット言語としてサポートしなければならない(MUST)。 Markdownの性質上、同じまたは後続の行でタグの説明を開始し、同じ方法でそれを解釈することは合法です。

したがって、次のタグは意味的に同じです。

/**
 * @var string This is a description.
 * @var string This is a
 *    description.
 * @var string
 *    This is a description.
 */

これの変形は、説明の代わりにタグ署名が使用される場合です。 ほとんどの場合、タグは実際には「注釈」になります。 タグ署名は、注釈にその操作に関するパラメータを提供することができる。

タグの署名が存在する場合、同じタグに記述が存在してはならない(MUST NOT)。

タグによって供給されるメタデータは、後続の「構造要素」の実際の実行時動作を変更する可能性があります。 この場合、「タグ」の代わりに「注釈」という用語が一般的に使用されます。

注釈は、これが範囲を超えているので、本明細書においてさらに詳細に説明されない。 この仕様は、アノテーションを実装するための基礎を提供します。

5.3.1. Tag Name

タグ名は、このタグによって表される情報のタイプ、または後続の「構造要素」に動作を注入する必要がある注釈の場合を示します。

注釈をサポートするために、個別のアプリケーションまたはアプリケーションのサブセット用に特別に設計された一連のタグを導入することができます(したがって、この仕様ではカバーされません)。

これらのタグまたは注釈は、以下のいずれかによって名前空間を提供しなければならない

  • タグ名の先頭にPHPスタイルの名前空間を付けるか
  • タグ名の先頭にハイフンを付けた単一のベンダー名を付ける

PHPスタイルの名前空間の接頭辞が付いたタグ名の例(接頭辞のスラッシュはOPTIONALです):

@\Doctrine\Orm\Mapping\Entity()

Note: PHPDoc標準は、この文書またはその後の追加や拡張で指定されていない限り、タグの意味を前提にしていません。

つまり、接頭辞の名前空間要素が提供されている限り、名前空間の別名を使用できます。 したがって、以下も合法です。

@Mapping\Entity()

あなた自身のライブラリやアプリケーションは、名前空間エイリアスをチェックして、これからFQCNを作るかもしれません。 これはこの規格に影響を与えません。

Important: PHPDoc標準を使用するツールは、そのアプリケーションに登録されている名前空間を解釈し、カスタム動作を適用することができる(MAY)。

ベンダー名とハイフンの接頭辞が付いたタグ名の例:

@phpdoc-event transformer.transform.pre

ベンダーまたは名前空間の接頭辞が付いていないタグ名は、この仕様書(第7章を参照)および/または正式な補遺に記述されなければならない(MUST)。

5.3.2. Tag Specialization

この標準で定義されたタグにニュアンスを与える方法を提供するために、基本セットを拡張することなく、タグ名の後にコロンを追加することにより、タグの特殊化を提供することができます。 タグ。 サポートされているタグの特殊化のリストは、時間の経過とともに変更される可能性があるため、このドキュメントでは維持されていません。 メタドキュメントには、タグごとの名前ベースの一連の推奨事項が含まれていますが、プロジェクトは、該当する場合は独自のタグ特殊化を自由に選択できます。

Important: PHPDoc標準を使用するツールは、そのアプリケーションに登録されている/理解されているタグ特殊化を解釈し、カスタム動作を適用することができますが、この標準で定義されている先行タグ名を実装するだけです。

For example:

@see:unit-test \Mapping\EntityTest::testGetId

上記のタグは、名前( ‘see')とタグの特殊化( 'unit-test')で構成されており、処理方法の単体テストとの関係を定義します。

5.3.3. Tag Signature

タグ・シグネチャは、現在のタグに固有の追加のメタデータを供給するために注釈に一般的に使用されます。

提供されたメタデータは、所有する注釈の振る舞いに影響を及ぼし、後に続く「構造要素」の振る舞いに影響を与える可能性があります。

署名の内容は、(タグ名に記述されているように)タグタイプによって決定され、この仕様の範囲外になる。 しかし、タグ署名には、説明や他の形式のメタデータを続けてはいけません。

5.4. Inline PHPDoc

特定のタグは “タグ"定義の最後に "Inline PHPDoc"セクションを持つかもしれません。 「インラインPHPDoc」は、中括弧で囲まれた「PHPDoc」要素であり、「タグ」定義で特に指定されていない限り、「タグ」シーケンスの最後にのみ存在します。 "Inline PHPDoc"要素は、提供されるべき記述を置き換えなければならない(MUST)。

@methodタグの例があります。 このタグは、 “インラインPHPDoc"を使用して、パラメータ、戻り値、または関数とメソッドでサポートされているその他のタグに関する追加情報を提供することができます。

An example of this is:

/**
 * @method int MyMagicMethod(string $argument1) {
 *     This is the summary for MyMagicMethod.
 *
 *     @param string $argument1 Description for argument 1.
 *
 *     @return int
 * }
 */
class MyMagicClass
{
    ...
}

この例では、MagicメソッドMyMagicMethodの@methodタグに、それに関連する完全なPHPDoc定義がどのようにして記述されているかを説明します。 この定義では、PHPDocの通常の使用に適用されるすべての制約、構文、およびタグも適用されます。

“Inline PHPDoc"要素の意味は、それが提供されている文脈によって異なります。 上の例では、 "Inline PHPDoc"は、メソッドの前にあるような通常のPHPDoc定義を提供します。

“Inline PHPDoc"要素の機能に関する混乱を避けるために、その使用法は文書化されているタグと場所に限定されていなければなりません。

5.5. Examples

次の例は、DocBlockの基本的な使い方を示しています。 第7章のタグのリストを読むことをお勧めします。

完全な例は、次の例のようになります。

/**
 * This is a Summary.
 *
 * This is a Description. It may span multiple lines
 * or contain 'code' examples using the _Markdown_ markup
 * language.
 *
 * @see Markdown
 *
 * @param int        $parameter1 A parameter description.
 * @param \Exception $e          Another parameter description.
 *
 * @\Doctrine\Orm\Mapper\Entity()
 *
 * @return string
 */
function test($parameter1, $e)
{
    ...
}

また、説明を省略することもできます。

/**
 * This is a Summary.
 *
 * @see Markdown
 *
 * @param int        $parameter1 A parameter description.
 * @param \Exception $parameter2 Another parameter description.
 *
 * @\Doctrine\Orm\Mapper\Entity()
 *
 * @return string
 */
function test($parameter1, $parameter2)
{
}

また、タグセクションも省略することもできます(ただし、パラメータと戻り値に関する情報が不足しているため、次の例では推奨されません)。

/**
 * This is a Summary.
 */
function test($parameter1, $parameter2)
{
}

次の例に示すように、DocBlockは1行にまたがることがあります。

/** @var \ArrayObject $array */
public $array = null;

いくつかのタグでは、次の例に示すように、「インラインPHPDoc」を使用することさえあります。

/**
 * @method int MyMagicMethod(string $argument1) {
 *     This is the summary for MyMagicMethod.
 *
 *     @param string $argument1 Description for argument 1.
 *
 *     @return int
 * }
 */
class MyMagicClass
{
    ...
}

6. 継承

「構造要素」を実装、拡張、または上書きする「構造要素」に関連付けられたPHPDocは、実装、拡張、または上書きされる「構造要素」に関連付けられたPHPDocから情報の一部を継承する機能を備えています。

“Structural Element"のすべてのタイプのPHPDocは、その部分がない場合、次の部分を継承しなければなりません:

“Structural Element"の各タイプのPHPDocは、どの "Structural Element"が関連付けられているかに応じて、特殊なタグのサブセットを継承しなければなりません(MUST)。

PHPDocにスーパー要素のPHPDocに存在するサマリーや説明などの部分がない場合、その部分は常に暗黙的に継承されます。 DocBlockがスーパーエレメントのDocBlockから情報を継承できるすべての要素のリストを次に示します。

  1. クラスまたはインタフェースのDocBlockは、それが拡張するクラスまたはインタフェースから情報を継承できます。
  2. プロパティのDocBlockは、スーパークラスで宣言されているのと同じ名前のプロパティから情報を継承できます。
  3. メソッドのDocBlockは、スーパークラスで宣言された同じ名前のメソッドから情報を継承できます。
  4. メソッドのDocBlockは、現在のクラスの実装されたインタフェースで宣言された、またはスーパークラスに実装されている同じ名前のメソッドから情報を継承できます。

For example:

\ SubClass :: myMethod()メソッドがあり、そのクラス\ SubClassがclass \ SuperClassを継承しているとしましょう。 また、class \ SuperClassには、同じ名前のメソッドがあります(例:\ SuperClass :: myMethod)。

上記の場合、\ SubClass :: myMethod()のDocBlockは、\ SuperClass :: myMethodのPHPDocから上記の部分を継承します。 したがって、@versionタグが再定義されていない場合、\ SubClass :: myMethod()は同じ@versionタグを持つとみなされます。

継承はクラス階層グラフのルートからリーフまで行われます。 つまり、ツリーの下に継承されたものは、上書きされない限り、一番上までバブルする必要があります。

6.1. Making inheritance explicit using the @inheritDoc tag

継承は暗黙的であるため、PHPDocに「構造要素」を含める必要はありません。 これは、PHPDocが意図的に省略されたのか、コードの作成者がドキュメントを追加するのを忘れてしまったのか、今やあいまいなので、混乱を招く可能性があります。

このあいまいさを解決するために、@inheritDocタグを使用して、この要素がスーパー要素から情報を継承することを示すことができます。

Example:

/**
 * This is a summary.
 */
class SuperClass 
{
}

/**
 * @inheritDoc
 */
class SubClass extends SuperClass
{
}

上の例では、SubClassのSummaryはSuperClassの要素のSummaryと同じであると見なすことができます。 これは “This is a summary"です。

6.2. Using the {@inheritDoc} inline tag to augment a Description

スーパーエレメントの説明を継承し、独自のテキストを追加して、「構造エレメント」固有の情報を提供したい場合もあります。 これは、{@inheritDoc}インラインタグを使用して行う必要があります。

{@inheritDoc}インラインタグは、その場所でスーパー要素の記述を注入または推論しなければならないことを示します。

Example:

/**
 * This is the Summary for this element.
 * 
 * {@inheritDoc}
 *
 * In addition this description will contain more information that
 * will provide a detailed piece of information specific to this
 * element.
 */

上記の例では、このPHPDocの説明は、{@inheritDoc}インラインタグで示されるスーパーエレメントの説明とそれに続く本文テキストの組み合わせであることが示されています。

6.3. Class Or Interface

この章のルートで定義されている継承された記述とタグに加えて、クラスまたはインタフェースは以下のタグを継承しなければならない(MUST)

クラスまたはインタフェースは、以下の非推奨タグを継承する必要があります(SHOULD):

スーパークラス(またはインタフェース)の@package名が子クラス(またはインタフェース)の@packageと同じでない場合は、@subpackageを継承してはいけません(MUST NOT)。

Example:

/**
 * @package    Framework
 * @subpackage Controllers
 */
class Framework_ActionController
{
    <...>
}

/**
 * @package My
 */
class My_ActionController extends Framework_ActionController
{
    <...>
}

上記の例では、My_ActionControllerはサブパッケージコントローラを継承してはならない(MUST NOT)。

6.4. Method

この章のルートで定義されている継承された説明とタグに加えて、クラスまたはインタフェースの関数またはメソッドは、次のタグを継承しなければなりません:

6.5. Constant Or Property

この章のルートで定義されている継承された説明とタグに加えて、クラスの定数またはプロパティは、次のタグを継承しなければなりません:

7. タグ

説明で特に言及されている場合を除いて、各タグは各 “DocBlock"で0回以上現れてもよい(MAY)。

7.1.. @api

@apiタグは、第三者による消費に適したものとして「構造要素」を宣言するために使用されます。

Syntax

@api

Description

@apiタグは、ライブラリやフレームワークのパブリックAPIコンポーネントを意図した、パブリックな可視性を持つ「構造要素」を表します。 公共の可視性を有する他の「構造要素」は、内部構造をサポートする役割を果たし、消費者が使用することは推奨されない。

Examples

/**
 * This method will not change until a major release.
 *
 * @api
 *
 * @return void
 */
function showVersion()
{
   <...>
}

7.2. @author

@authorタグは、「構造要素」の作成者を文書化するために使用されます。

Syntax

@author [name] [<email address>]

Description

@authorタグは、誰が “構造要素"を作成したか、またはそれを大幅に変更したことを示すために使用できます。 このタグには、電子メールアドレスも含まれています。 電子メールアドレスが提供されている場合は、著者の名前に従わなければならず、シェブロンまたは山括弧で囲まれていなければならず、RFC 2822で定義されている構文を遵守しなければならない。

Examples

/**
 * @author My Name
 * @author My Name <my.name@example.com>
 */

7.3. @category [deprecated]

@categoryタグは、パッケージのグループをまとめて整理するために使用されますが、@packageタグで最上位を占めることになっています。 そのため、このタグの使用は推奨されません。

Syntax

@category [description]

Description

@categoryタグは、いくつかの@packagesを1つのカテゴリにグループ化するための、デファクトスタンダードでのものでした。 これらのカテゴリは、APIドキュメントの生成を支援するために使用できます。

これは、元の標準で定義されている@packageタグに複数の階層レベルが含まれていなかったために必要でした。 これは変更されているため、このタグを使用しないでください。

使用方法の詳細については、@packageのドキュメントを参照してください。

このタグは “DocBlock"に複数回現れてはならない(MUST NOT)。

Examples

/**
 * File-Level DocBlock
 *
 * @category MyCategory
 * @package  MyPackage
 */

7.4. @copyright

@copyrightタグは、「構造要素」の著作権情報を文書化するために使用されます。

Syntax

@copyright <description>

Description

@copyrightタグは、 “Structural Element"に著作権を持つ人を定義します。 このタグで示される著作権は、特に明記しない限り、適用される「構造要素」およびすべての子要素に適用されます。

Examples

/**
 * @copyright 1997-2005 The PHP Group
 */

7.5. @deprecated

@deprecatedタグは、「構造要素」が非推奨であり、将来のバージョンで削除されることを示すために使用されます。

Syntax

@deprecated [<"Semantic Version">][:<"Semantic Version">] [<description>]

Description

@deprecatedタグは、関連する ‘構造要素'が将来のバージョンで削除されることを宣言します。 使用されなくなると、その使用法は推奨されません。

このタグは、バージョン番号の範囲の意味で最大2つのバージョン番号を指定することができる(MAY):

「開始バージョン」と呼ばれる最初のバージョン番号は、関連する要素が廃止されたバージョンを示します。

「終了バージョン」と呼ばれる第2のバージョン番号は、関連する要素が削除のためにスケジュールされているバージョンを示す。

‘終了バージョン'が指定されている場合、関連する '構造要素'は '終了バージョン'に存在しなくなり、そのバージョン以降のバージョンではそれ以上の通知なしに削除される可能性がありますが、以前のすべてのバージョンに存在しなければなりません。

「開始バージョン」と「終了バージョン」の両方を指定することを推奨します。 この場合、2つのバージョン番号はコロン( )で区切られなければなりません(MUST)。

‘開始バージョン'は省略してもよい(MAY)。 この場合、 '終了バージョン'の前にコロンを付ける必要があります。

このタグは、関連する要素がなぜ非難されたのかを説明する追加の記述を提供してもよい(MAY)。

関連する要素が別の要素によって置き換えられた場合、新しい要素を指す同じ「PHPDoc」内に@seeタグを追加することが推奨されます。

Examples

/**
 * @deprecated
 *
 * @deprecated 1.0.0:2.0.0
 * @see \New\Recommended::method()
 *
 * @deprecated 1.0.0
 *
 * @deprecated :2.0.0
 *
 * @deprecated No longer used by internal code and not recommended.
 *
 * @deprecated 1.0.0 No longer used by internal code and not recommended.
 */

7.6. @example

@exampleタグは、現在の「構造要素」の使用例を含む外部ソースコードファイルにリンクするために使用されます。 インライン版が存在し、サンプルファイルのコードを説明と共にインラインで表示することができます。

Syntax

@example [URI] [<description>]

or inline:

{@example [URI] [:<start>..<end>]}

Description

サンプルタグは、現在の「構造要素」の目的と使用法を示すサンプルコードを含むファイルを参照します。 いくつかのシナリオが記述されている場合、「構造要素」ごとに複数のサンプルタグを使用できます。

exampleタグで提供されるURIは、次の規則に従って解決されます:

  1. URIphar://http:///C:\のようなスキームやルートフォルダ指定子によって処理された場合、絶対パスと見なされます。
  2. URI相対パスであるとみなされ、サンプルファイルの場所が指定されている場合は、指定された場所を基準にしたパスが解決されます。
  3. 前のパスが読めない場合、またはユーザーがパスを提供していない場合、アプリケーションはexampleタグを含むソースファイルと同じフォルダ内のフォルダ ‘examples'を検索しようとします。 見つかった場合、サンプルタグで指定された相対パスと見つかったフォルダを組み合わせてパスを解決しようとする必要があります。
  4. アプリケーションが以前のルールで指定されたパスを解決できなかった場合は、 “Structural Element"のソースファイルを含むプロジェクトのルートフォルダに読み取り可能なフォルダ ‘examples'があるかどうかを確認する必要があります。

    プロジェクトのルートフォルダは、使用中のアプリケーションによって処理されているすべてのファイルに共通する最も高いフォルダです。

消費者がサンプルファイルの内容を表示しようとする場合は、構文強調表示ソリューションを使用してユーザーエクスペリエンスを改善することが推奨されます。

上記のルールは、インラインタグにも適用されます。 インラインタグには、説明に表示されるコード行を制限する2つの追加パラメータがあります。 このため、消費アプリケーションは、インラインサンプルタグが使用される場合には、サンプルコードを表示する必要があります。

開始引数と終了引数は省略することができますが、いずれかを使用して明瞭な視覚的指示を与える場合は、省略記号を残す必要があります。 PHPsubstr関数で指定されているのと同じ規則が、開始と終了の制限に関して有効です。

消費しているアプリケーションは、以前の標準で使用されていたリミットフォーマットをサポートすることを選択してもよいが、このPSRごとに推奨されない。 前の構文は{@example [URI] [] []}であり、substr関数と同じ規則をサポートしていませんでした。

Examples

/**
 * Counts the number of items.
 * {@example http://example.com/foo-inline.https:2..8}
 *
 * @example http://example.com/foo.phps
 *
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

7.7. @global

TODO: この項目の定義については、@varタグによって部分的または全体的に置き換えられるかどうかについて議論する必要があります。

@globalタグは、グローバル変数またはその使用法を示すために使用されます。

Syntax

@global ["Type"] [name]
@global ["Type"] [description]

Description

グローバル変数を宣言する標準的な方法はないので、グローバル変数の定義に先行するDocBlockで@globalタグを使用することができる(MAY)。 @globalの以前の使用法をサポートするために、関数の前のDocBlockに適用される別の構文があり、グローバル変数の使用を文書化するために使用されます。 言い換えれば、定義と使用の2つの使用法があります。

Syntax for the Global’s Definition

@globalタグは、グローバル変数DocBlockごとに1つしか許可されません。 他の要素やDocBlockが発生する前に、グローバル変数DocBlockの後にグローバル変数の定義を続ける必要があります。

名前は、ソースで宣言されているグローバル変数の正確な名前でなければなりません(MUST)。

Syntax for the Global’s Usage

関数/メソッド@global構文は、関数内の大域変数の使用を文書化するために使用されるかもしれないし、$を3番目の単語から始めてはならない(MUST NOT)。 宣言されたグローバル変数とプロジェクトで文書化された変数が一致すると、 “タイプ"は無視されます。

Examples

(TODO: このタグの例を追加する必要があります)

7.8. @internal

@internalタグは、関連する「構造要素」がこのアプリケーションまたはライブラリの内部構造体であることを示すために使用されます。 また、このソフトウェアの開発者にのみ適用可能なテキストを挿入するために、説明内で使用することもできます。

Syntax

@internal

or inline:

{@internal [description]}}

このタグのインラインバージョンは、他のインラインタグとは異なり、テキストだけでなく他のインラインタグも含むことがあります。 読みやすさを高め、タグの解析を簡単にするには、単一のタグではなく、二重の閉じ括弧でタグを終了する必要があります。

Description

@internalタグは@apiタグのカウンターパートとして使用できます。 これは、関連付けられた「構造要素」がこのソフトウェアの内部動作のためにのみ使用されていることを示します。

PHPDocのコメントからドキュメンテーションを生成する際、ユーザが内部要素を含めるべきであることを明示的に示さない限り、関連する要素を非表示にすることが推奨されます。

@internalをさらに使用すると、説明に内部コメントまたは追加説明テキストをインラインで追加できます。 これは、例えば、このソフトウェアのソースコードから文書を生成する際に、ビジネスクリティカルで混乱している特定の情報を保留するために行うことができます。

Examples

カウント関数をこのプロジェクトの内部としてマークする:

/**
 * @internal
 *
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

/**
 * Counts the number of Foo.
 *
 * {@internal Silently adds one extra Foo to compensate for lack of Foo }}
 *
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

7.9. @license

@licenseタグは、関連する「構造要素」に適用されるライセンスを示すために使用されます。

Syntax

@license [<SPDX identifier>|URI] [name]

Description

@licenseタグは、ユーザーにライセンス情報を提供します。これは、 ‘Structural Elements'とその子要素に適用されます。

最初のパラメータは、SPDXオープンソースライセンスレジストリで定義されている「SPDX識別子」か、フルライセンステキストを含むドキュメントのURLでなければなりません。

第2のパラメータは、適用されるライセンスの正式名称であってもよい(MAY)。

「SPDX識別子」を指定し、@ licenseタグをファイルレベルの「PHPDoc」にのみ適用することをお勧めします。単一のファイル内の複数の異なるライセンスが、どのライセンスがいつ適用されるかについて混乱を招く可能性があるためです。

複数のライセンスが適用される場合は、該当するライセンスごとに@licenseタグが1つ必要です。

Examples

/**
 * @license MIT
 *
 * @license GPL-2.0+
 *
 * @license http://www.spdx.org/licenses/MIT MIT License
 */

7.10. @link [deprecated]

このタグは @ seeタグのために推奨されていません。この仕様はURIに関連している可能性があります。

@linkタグは、関連する “構造要素"とウェブサイトとの間のカスタムリレーションを示します。 これは絶対URIで識別されます。

Syntax

@link [URI] [description]

or inline

@link [URI] [description]

Description

@linkタグを使用して、構造要素またはインラインで使用される記述の一部とURIとの間のリレーションまたはリンクを定義できます。

URIRFC2396で指定されているように完全であり、かつ合致しなければならない(MUST)。

@linkタグには、このオカレンスによって定義された関係のタイプを示すために説明が付加されてもよい(MAY)。

Examples

/**
 * @link http://example.com/my/bar Documentation of Foo.
 *
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

/**
 * This method counts the occurrences of Foo.
 *
 * When no more Foo ({@link http://example.com/my/bar}) are given this
 * function will add one as there must always be one Foo.
 *
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

7.11. @method

@methodは、どの「マジック」メソッドが呼び出し可能であるかをクラスが知ることを可能にします。

Syntax

@method [return type] [name]([type] [parameter], [...]) [description]

Description

@methodタグは、あるクラスが __call()魔法のメソッドを含み、いくつかの明確な用途を定義している状況で使用されます。

これの例は、親クラスが __call()を持ち、事前定義されたプロパティ用の動的getterまたはsetterを持つ子クラスです。 子は、どのゲッターとセッターが存在する必要があるかを知っていますが、それを提供するために __call()メソッドを使うために親クラスに依存しています。 この状況では、子クラスは、各魔法のsetterメソッドまたはgetterメソッドの@methodタグを持ちます。

@methodタグは、署名にそれらの型を含めることによって、引数の型と戻り値の型を通信することができます。

意図したメソッドに戻り値がない場合、戻り値の型は省略することができます(MAY)。 その場合は「無効」となります。

@methodタグは、 classinterfaceに関連付けられていないPHPDocで使われてはならない(MUST NOT)。

Examples

class Parent
{
    public function __call()
    {
        <...>
    }
}

/**
 * @method string getString()
 * @method void setInteger(int $integer)
 * @method setString(int $integer)
 */
class Child extends Parent
{
    <...>
}

7.12. @package

@packageタグは、「構造要素」を論理的な細分に分類するために使用されます。

Syntax

@package [level 1]\[level 2]\[etc.]

Description

@packageタグは、ネームスペースの対応または補足として使用できます。 名前空間は、@packageタグが要素を別の階層でグループ化することができる論理的な細分割を提供できる「構造要素」の機能的な細分化を提供します。

ボード全体で、論理区画と機能区画の両方が等しい場合、メンテナンスのオーバーヘッドを防ぐために、@packageタグを使用することは推奨されません。

論理階層の各レベルは、ネームスペースに慣れているために、バックスラッシュ( \)で区切らなければなりません。 階層構造は無限深度でもよいが、深度を6レベル以下に保つことが推奨される。

@packageは、定義されている場所によって異なる「構造要素」に適用されます。

  1. @packageが ファイルレベル DocBlockで定義されている場合、適用可能なファイルの次の要素にのみ適用されます。

  2. @packageが namespace-level または class-level DocBlockで定義されている場合、パッケージはその名前空間、クラスまたはインタフェース、およびそれらに含まれる要素に適用されます。 これは、@packageタグを持つ名前空間に含まれる関数が、そのパッケージを想定していることを意味します。

このタグは “DocBlock"に複数回現れてはならない(MUST NOT)。

Examples

/**
 * @package PSR\Documentation\API
 */

7.13. @param

@paramタグは、関数またはメソッドの単一のパラメータを記述するために使用されます。

Syntax

@param ["Type"] [name] [<description>]

Description

@paramタグを使用すると、関数またはメソッドの単一のパラメータの型と関数を文書化することができます。 それが提供されるとき、それは期待されるものを示すために “タイプ"を含まなければなりません。 一方、説明はOPTIONALですが、RECOMMENDEDです。 オプション配列などの複雑な構造の場合は、オプション配列を記述するために "Inline PHPDoc"を使用することを推奨します。

@paramタグは、複数行記述を持ち、明示的な区切りを必要としません。

すべての機能と方法でこのタグを使用することを文書化するときは、RECOMMENDEDを推奨します。

このタグは、 “PHPDoc"内のパラメータごとに複数回出現してはならず、メソッドまたは関数型の "構造要素” に限定されています。

Examples

/**
 * Counts the number of items in the provided array.
 *
 * @param mixed[] $items Array structure to count the elements of.
 *
 * @return int Returns the number of elements.
 */
function count(array $items)
{
    <...>
}

次の例は、「必須」と「ラベル」という2つの要素を持つオプション配列をドキュメント化するための「インラインPHPDoc」の使用方法を示しています。

/**
 * Initializes this class with the given options.
 *
 * @param array $options {
 *     @var bool   $required Whether this element is required
 *     @var string $label    The display name for this element
 * }
 */
public function __construct(array $options = array())
{
    <...>
}

7.14. @property

@propertyタグは、クラスがどの「魔法」プロパティが存在するかを知ることを可能にします。

Syntax

@property ["Type"] [name] [<description>]

Description

@propertyタグは、あるクラスが __get()__set()魔法のメソッドを含み、特定の名前を許す状況で使われます。

この例は、親が __get()を持つ子クラスです。 子は存在する必要があるプロパティを知っていますが、それを提供するために __get()メソッドを使うために親クラスに依存しています。 この状況では、子クラスは各魔法のプロパティのために@propertyタグを持ちます。

@propertyタグは、 class または interface に関連付けられていない “PHPDoc"では使用できません。

Examples

class Parent
{
    public function __get()
    {
        <...>
    }
}

/**
 * @property string $myProperty
 */
class Child extends Parent
{
    <...>
}

7.15. @return

@returnタグは、関数やメソッドの戻り値を文書化するために使用されます。

Syntax

@return <"Type"> [description]

Description

@returnタグを使用すると、関数またはメソッドの戻り値の型を文書化することができます。 提供されるとき、返されるものを示すために “Type"(付録A参照)を含まなければなりません。 結合配列のような複雑な戻り構造の場合には、もう一方の説明はOPTIONALですが、RECOMMENDEDです。

@returnタグは、複数行記述を持ち、明示的な区切りを必要としません。

すべての関数とメソッドでこのタグを使用することを推奨します。 個々のプロジェクトのコーディング標準で定義されているこの勧告の例外は、次のようなものであってもよい:

return 値を持たない関数とメソッド : @returnタグをここで省略してもよい(MAY)。この場合、インタプリタはこれを @return voidが提供されているかのように解釈しなければならない(MUST)。

このタグは、 “DocBlock"内で複数回出現してはならない(MUST NOT)。メソッドや関数の "構造要素"の "DocBlock"に限定されている。

Examples

/**
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

/**
 * @return string|null The label's text or null if none provided.
 */
function getLabel()
{
    <...>
}

7.16. @see

@seeタグは、関連する「構造要素」からWebサイトまたは他の「構造要素」への参照を示します。

Syntax

@see [URI | "FQSEN"] [<description>]

Description

@seeタグは、他の「構造要素」やURIへの参照を定義するために使用できます。

別の「構造要素」への参照を定義するときは、二重コロンを付加し、その要素の名前(「FQSEN」とも呼ばれます)を指定することで特定の要素を参照できます。

URIは、RFC 2396で指定されているように、完全で整形式でなければならない(MUST)。

@seeタグには、要素とそのターゲットの間の関係に関する追加情報を提供する記述があるべきです(SHOULD)。 さらに、@seeタグは、この関係にさらなる定義を追加するために、タグ特化を持つことができます(MAY)。

Examples

/**
 * @see number_of() :alias:
 * @see MyClass::$items           For the property whose items are counted.
 * @see MyClass::setItems()       To set the items for this collection.
 * @see http://example.com/my/bar Documentation of Foo.
 *
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

7.17. @since

@sinceタグは、その要素に「バージョン管理」の何らかの記述を使用して、要素が導入または変更されたときに_を表すのに使用されます。

Syntax

@since [<"Semantic Version">] [<description>]

Description

要素の導入または変更の「バージョン」を文書化します。

バージョンが意味論的バージョン番号(x.x.x)と一致することが推奨されており、追加情報を提供するための説明があるかもしれません。

この情報を使用して、特定の要素に必要なアプリケーションバージョンがコンシューマに通知される一連のAPIドキュメントを生成できます。

@sinceタグは要素の現在のバージョンを表示するべきではない(SHOULD NOT)、その目的のために@versionタグを使用してもよい(MAY)。

Examples

/**
 * This is Foo
 * @version 2.1.7 MyApp
 * @since 2.0.0 introduced
 */
class Foo
{
    /**
     * Make a bar.
     *
     * @since 2.1.5 bar($arg1 = '', $arg2 = null)
     *        introduced the optional $arg2
     * @since 2.1.0 bar($arg1 = '')
     *        introduced the optional $arg1
     * @since 2.0.0 bar()
     *        introduced new method bar()
     */
    public function bar($arg1 = '', $arg2 = null)
    {
        <...>
    }
}

7.18. @subpackage [deprecated]

@subpackageタグは、「構造要素」を論理的な細分に分類するために使用されます。

Syntax

@subpackage [name]

Description

@subpackageタグは、ネームスペースに対応したり、サプリメントとして使うことができる(MAY)。 名前空間は、@subpackageタグが要素を別の階層でグループ化することができるような論理的な細分化を提供できる「構造要素」の機能的な細分化を提供します。

ボード全体で、論理区画と機能区画が等しい場合、メンテナンスのオーバーヘッドを防ぐために、@subpackageタグを使用することは推奨されません。

@subpackageタグは、特定の一連のDocBlocksでのみ使用する必要があります(@packageタグのドキュメントを参照)。

このタグは@packageタグに付随しなければならず、DocBlockごとに2回以上現れてはならない(MUST NOT)。

Examples

/**
 * @package PSR
 * @subpackage Documentation\API
 */

7.19. @throws

@throwsタグは、「構造要素」が特定のタイプの例外をスローするかどうかを示すために使用されます。

Syntax

@throws ["Type"] [<description>]

Description

@throwsタグは、「構造要素」が特定のタイプのエラーをスローすることを示すために使用されるかもしれません。

このタグで提供される型は、Exceptionクラスまたはそのサブクラスのオブジェクトを表現しなければならない(MUST)。

このタグは、どのエラーが発生し、どのような状況で発生するかをドキュメントに示すために使用されます。 例外がスローされる理由を説明する記述を提供することが推奨される。

このタグは、たとえ同じ型であっても、例外が発生するたびに発生することが推奨されます。 すべての発生を文書化することにより、詳細なビューが作成され、消費者はどのエラーをチェックするかを知る。

Examples

/**
 * Counts the number of items in the provided array.
 *
 * @param mixed[] $array Array structure to count the elements of.
 *
 * @throws InvalidArgumentException if the provided argument is not of type
 *     'array'.
 *
 * @return int Returns the number of elements.
 */
function count($items)
{
    <...>
}

7.20. @todo

@todoタグは、関連する「構造要素」上でまだ開発アクティビティを実行する必要があるかどうかを示すために使用されます。

Syntax

@todo [description]

Description

@todoタグは、関連する「構造要素」を取り囲むアクティビティが引き続き発生する必要があることを示すために使用されます。 各タグは元の著者の意図を伝える記述を伴わなければならない(MUST)。 しかしながら、これは発行番号を提供するのと同じくらい短いかもしれません。

Examples

/**
 * Counts the number of items in the provided array.
 *
 * @todo add an array parameter to count
 *
 * @return int Returns the number of elements.
 */
function count()
{
    <...>
}

7.21. @uses

現在の「構造要素」がターゲットとして提供される「構造要素」またはプロジェクトファイルを消費するかどうかを示します。

Syntax

@uses [file | "FQSEN"] [<description>]

Description

@ usesタグは、関連する「構造要素」のいずれかの部分が、別の「構造要素」または現在のプロジェクトにあるファイルを使用するか、または消費するかどうかを示します。

別の「構造要素」への参照を定義するときは、二重コロンを付加し、その要素の名前(「FQSEN」とも呼ばれます)を指定することで特定の要素を参照できます。

このプロジェクトに含まれるファイルは、このタグで参照できます。 これは、例えば、コントローラとテンプレートファイル(View)との関係を示すために使用できます。

このタグは、システム外の要素との関係を示すために使用されてはならない(MUST NOT)ので、URLは使用できません。 外部の要素との関係を示すために、@seeタグを使うことができます。

このタグを消費するアプリケーション(ジェネレータなど)は、宛先要素に @ used-byタグを付けることを推奨します。 これは、双方向の経験を提供し、静的分析を可能にするために使用できます。

Examples

/**
 * @uses \SimpleXMLElement::__construct()
 */
function initializeXml()
{
    <...>
}
/**
 * @uses MyView.php
 */
function executeMyView()
{
    <...>
}

7.22. @var

@varタグを使用して、次の「構造要素」の「タイプ」を文書化することができます。

  • クラスとグローバルスコープの両方の定数
  • プロパティ
  • グローバルスコープとローカルスコープの両方の変数

Syntax

@var ["Type"] [element_name] [<description>]

Description

@varタグは、どのタイプのデータが定数、プロパティ、または変数の値で表されるかを定義します。

型や曖昧さが不明で不明な各定数やプロパティの定義や変数の前には、@varタグを含むDocBlockを置くべきです(SHOULD)。 他の変数の前に@varタグを含むDocBlockを置くことができる(MAY)。

@varタグは、それが文書化した要素の名前を含まなければなりません。 例外は、プロパティ宣言が単一のプロパティのみを参照する場合です。 この場合、プロパティの名前は省略されてもよい(MAY)。

これは、複合ステートメントを使用して一連の定数またはプロパティを定義するときに使用されます。 このような複合文は、複数の項目が表されている間に1つのDocBlockしか持つことができません。

Examples

/** @var int $int This is a counter. */
$int = 0;

// there should be no docblock here
$int++;

または:

class Foo
{
  /** @var string|null Should contain a description */
  protected $description = null;

  public function setDescription($description)
  {
      // there should be no docblock here
      $this->description = $description;
  }
}

別の例は、foreach内の変数を明示的に文書化することです。 多くのIDEがこの情報を使って自動補完を手助けしています:

/** @var \Sqlite3 $sqlite */
foreach($connections as $sqlite) {
    // there should be no docblock here
    $sqlite->open('/my/database/path');
    <...>
}

コンパウンドステートメントでさえ文書化されるかもしれません:

class Foo
{
  protected 
      /**
       * @var string Should contain a description
       */
      $name, 
      /**
       * @var string Should contain a description
       */
      $description;

}

または定数:

class Foo
{
  const 
      /**
       * @var string Should contain a description
       */
      MY_CONST1 = "1", 
      /**
       * @var string Should contain a description
       */
      MY_CONST2 = "2";

}

7.23. @version

@versionタグは、要素への「バージョン管理」の記述を示すために使用されます。

Syntax

@version ["Semantic Version"] [<description>]

Description

要素の現在の「バージョン」を記録します。

この情報は、特定のバージョンの要素についてコンシューマに通知される一連のAPIドキュメントを生成するために使用できます。

Semantic Versioning Standard version 2.0で説明されているように、バージョン番号がセマンティックバージョン番号と一致することが推奨される。

バージョンコントロールシステムのバージョンベクトルもサポートされていますが、次の形式に従う必要があります:

name-of-vcs: $vector$

追加のバージョン固有の情報を伝えるために、説明を提供することができる(MAY)。

@versionタグは、最後に変更された、または導入バージョンの要素を表示するために使用されることはできません。 そのためには、@sinceタグを使用するべきです(SHOULD)。

Examples

/**
 * File for class Foo
 * @version 2.1.7 MyApp
 *          (this string denotes the application's overall version number)
 * @version @package_version@
 *          (this PEAR replacement keyword expands upon package installation)
 * @version $Id$
 *          (this CVS keyword expands to show the CVS file revision number)
 */

/**
 * This is Foo
 */
class Foo
{
  <...>
}

付録 A. 型

ABNF

タイプは以下のABNF定義:

type-expression  = type *("|" type)
type             = class-name / keyword / array
array            = (type / array-expression) "[]" / generic
array-expression = "(" type-expression ")"
generic          = collection-type "<" [type-expression "," *SP] type-expression ">"
collection-type  = class-name / "array"
class-name       = ["\"] label *("\" label)
label            = (ALPHA / %x7F-FF) *(ALPHA / DIGIT / %x7F-FF)
keyword          = "array" / "bool" / "callable" / "false" / "float" / "int" / "mixed" / "null" / "object" /
keyword          = "resource" / "self" / "static" / "string" / "true" / "void" / "$this"

Details

「タイプ」が使用されるとき、ユーザは以下に詳述するように値または値のセットを期待する。

“タイプ"が複数のタイプで構成されている場合、これらは縦棒記号(|)で区切らなければなりません。 この仕様をサポートするすべてのインタプリタはこれを認識し、評価する前に "タイプ"を分割しなければなりません(MUST)。

例: @return int|null

Arrays

“Type"で表される値は配列になります。 タイプは、以下のオプションの1つのフォーマットに従って定義されなければならない(MUST)

  1. 指定されていない場合、表現された配列の内容の定義は与えられません。 例: @return array

  2. 型の定義は、各配列値の型を読者に通知します。 指定された配列内の各値に対して1つの型しか期待されません。

    例: @return int[]

    mixed も単一の型であり、このキーワードを使用すると、各配列の値に可能な型が含まれていることを示すことができます。

  3. 複数の型を含むと指定されている場合、型定義は各配列値の型を読者に通知します。 各値は、指定されたタイプのいずれかになります。 例: @return (int|string)[]

  4. ジェネリックス記法を使用して指定されている場合、この記法の説明については、次の章「コレクション」を参照してください。

Collections

“Type"で表される値は、値を持つキーのリストを含むクラスであるCollectionでもかまいません。 コレクションは、JavaGenericsから派生したフォーマットを使用して表すことができます。 ジェネリックスタイルの表記法と呼ばれています。

ジェネリックス形式の表記法では、クラス名または配列キーワードを指定し、その後に角括弧で囲まれた値の型を指定する必要があります。

例:この要素が一連の文字列のみを含むArrayObjectクラスのオブジェクトを返すことを示す。

@return \ArrayObject<string>

Collection内の値の型は別の配列であっても、別のCollectionであってもよい(MAY)

@return \ArrayObject<\ArrayObject<int>>

コレクションは、値の型を示す識別子の前に角カッコの間に追加の型定義を追加することによって、コレクションのキーの型をオプションで定義することができます(MAY)。 これら2つはコンマで区切ってください。

例:整数キーを持つ文字列のリストを含むArrayObjectコレクションを宣言する。

@return \ArrayObject<int, string>

値の型またはキーは、いくつかの異なる型から成っていてもよい(MAY)。 角型の角かっこの間に縦型の記号で個々の型を分けて表現できます。

@return \ArrayObject<string|bool>

Valid Class Name

この型が記述されているコンテキストから見た有効なクラス名。 したがって、これはFQCN(Fully Qualified Class Name)か、ネームスペース内にローカル名が存在する場合があります。

この型が適用される要素は、このクラスのインスタンスまたは指定されたクラスの(子)子であるクラスのインスタンスのいずれかです。

上記の性質のために、この情報を収集して形状化するアプリケーションでは、クラスの各表現で子クラスのリストを表示することが推奨されます。 これにより、どのクラスが型として受け入れられるかは、ユーザにとっては明らかになります。

Keyword

このタイプの目的を定義するキーワード。 すべての要素がクラスによって決定されるわけではありませんが、開発者がDocBlockの対象となるコードを理解するのに役立つ分類の価値はあります。

Note:

これらのキーワードのほとんどはPHPではクラス名として使用でき、実際のクラスと区別することは困難です。 ほとんどのクラス名は大文字の最初の文字で始まるので、そのようなキーワードは小文字でなければならない(MUST)ので、コード内でこれらの名前のクラスを使用すべきではない(SHOULD NOT)。

これらのキーワードの名前を持つクラスに名前を付けない理由はたくさんありますが、それはこの仕様の範囲を超えています。

このPSRで認識されるキーワードは次のとおりです:

  1. string, この型が適用される要素は2進文字列です。

  2. int, この型が適用される要素は、整数または整数です。

  3. bool, この型が適用される要素は、状態が「TRUE」または「FALSE」のみです。

  4. float, この型が適用される要素は、連続する、または実数です。

  5. object, この型が適用される要素は、未定義クラスのインスタンスです。

  6. mixed, この型が適用される要素は、ここで指定されたどんな型でも構いません。 どのタイプが使用されるかは、コンパイル時には分かりません。

  7. array, この型が適用される要素は値の配列です。

  8. resource, この型が適用される要素はPHPの定義ごとのリソースです。

  9. void, この型は、通常、メソッドまたは関数の戻り値の型を定義するときにのみ使用されます。

    基本的な定義では、この型で指定された要素には値が含まれておらず、ユーザーは検索された値に頼るべきではありません。

    Example 1:

    /**
     * @return void
     */
    function outputHello()
    {
        echo 'Hello world';
    }
上記の例では、return文が指定されていないため、戻り値は決定されません。

**Example 2:**
    /**
     * @param bool $hi when true 'Hello world' is echo-ed.
     *
     * @return void
     */
    function outputHello($quiet)
    {
        if ($quiet} {
            return;
        }
        echo 'Hello world';
    }
この例では、関数には指定された値のないreturn文が含まれています。 実際の値が指定されていないので、これも `void`型として扱います。
  1. null, この型が適用される要素は「NULL」値であり、技術的には存在しない。

    void と比較して大きな違いは、この型は、記述された要素がいつでも明示的なNULL値を含むことができるあらゆる状況で使用されることです。

    Example 1:

    /**
     * @return null
     */
    function foo()
    {
        echo 'Hello world';
        return null;
    }
この型は、何も返されない可能性があることを示すために、通常、別の型と組み合わせて使用されます。

**Example 2:**
    /**
     * @param bool $create_new When true returns a new stdClass.
     *
     * @return stdClass|null
     */
    function foo($create_new)
    {
        if ($create_new) {
            return new stdClass();
        }
        return null;
    }
  1. callable, この型が適用される要素は、関数呼び出しへのポインタです。 これは、pseudo-typesまたはcallableのセクションに関するPHPマニュアルで定義されている任意のタイプの呼び出し可能関数です。

  2. false or true, この型が適用される要素は、値が「TRUE」または「FALSE」になります。 この要素から他の値は返されません。

  3. self, この型が適用される要素は、文書化された要素がもともと含まれていたものと同じクラスです。

    Example:

    メソッドcはクラスAに含まれています。 DocBlockは、戻り値がself型であることを示します。 このように、メソッドcはクラスAのインスタンスを返します。

    これは、継承が関与している混乱する状況につながる可能性があります。

    Example (previous example situation still applies):

    クラス B は、クラスA を拡張し、メソッド c を再定義していません。 したがって、クラス Bからメソッド c を呼び出すことができます。

    この状況では、「自己」がクラス A または B のいずれかと解釈される可能性があるため、あいまいさが発生する可能性があります。 これらの場合、 selfは、self型を含むDocBlockが記述されているクラスのインスタンスであると解釈されなければなりません。

    上の例では、 selfはクラス A の中でメソッド c で定義されているので常にクラス A を参照しなければならない(MUST)。

    上記の性質のために、この情報を収集して形状化するアプリケーションでは、クラスの各表現で子クラスのリストを表示することが推奨されます。 これにより、どのクラスが型として受け入れられるかは、ユーザにとっては明らかになります。

  4. static, この型が適用される要素は、文書化された要素と同じクラスです。あるいは、サブクラスで見つかった場合、元のクラスの代わりにそのサブクラスの型です。

    このキーワードは、PHPで定義されている静的メソッド、プロパティ、変数修飾子ではありませんと同じように動作します。

  5. $ this, この型が適用される要素は、与えられたコンテキストの現在のクラスと同じ正確なインスタンスです この型は、返されるインスタンスが同じクラスである必要はなく、同じインスタンスである必要があるだけでなく、さらに厳格な `static ‘バージョンです。

    このタイプは、Fluent Interfaceデザインパターンを実装するメソッドの戻り値としてよく使用されます。