目次

PSR-5: PHPDoc Standard(Draft)

y2sunlight 2020-04-28

本章は、若干の補足を加筆してはいるものの単にPSRのサイトを日本語に翻訳したものに過ぎません。英語が堪能な方は原文をご参照下さい。翻訳に当たっては、基本的に機械翻訳を使い、理解できない部分は独断で意訳しております。拙い訳では御座いますが恥を忍んで投稿しておりますので、ご指摘など御座いましたらコメントを頂ければ幸いです。

関連記事


PSR-5: PHPDoc の中で使用されている用語「タグカタログPSR(Tag Catalog PSR)」はPSR-19: PHPDoc tags を指します。この2つのPSRは元々1つだったものが分割したものです。


PSR-5: PHPDoc規約(ドラフト)

原文より翻訳 PSR-5: PHPDoc 2020-04-28 現在

1. はじめに

このPSRの主な目的は、PHPDoc規約の完全かつ正式な定義を提供することです。このPSRは、その前身である https://www.phpdoc.org/phpDocumentor 1.x に関連付けられた事実上のPHPDoc規約からは逸れており、PHP言語の新しい機能のサポートを提供し、その前身のいくつかの欠点に対処しています。


2. このドキュメントで使用される規則

このドキュメントのキーワード MUST , MUST NOT , REQUIRED , SHALL , SHALL NOT , SHOULD , SHOULD NOT , RECOMMENDED , MAY 及び OPTIONAL は、 RFC 2119で説明されているように解釈して下さい。

RFC 2119の説明
MUST, REQUIRED, SHALL — 絶対必要
MUST NOT, SHALL NOT — 絶対禁止
SHOULD, RECOMMENDED — 推奨(但し、無視できる特定の正当な理由が存在するかもしれない)
SHOULD NOT — 推奨できない(但し、許可できる特定の正当な理由が存在するかもしれない)
MAY, OPTIONAL — オプション


3. 定義

  • require(_once)
  • include(_once)
  • クラス
  • インターフェース
  • トレイト
  • 関数(メソッドを含む)
  • プロパティ
  • 定数
  • 変数(ローカルとグローバルスコープの両方)

構造的要素の前に、DocBlock を付けることをお勧めします (RECOMMENDED)。DocBlock を構造的要素の直ぐ前に置くことは一般的な方法ですが、いくつかの空行で区切られる場合もあります (MAY)。

例:

/** @var int $int This is a counter. */
/** @var int $int これはカウンターです */
$int = 0;
 
// there should be no docblock here
// ここには docblock があってはなりません
$int++;

または

/**
 * This class acts as an example on where to position a DocBlock.
 * このクラスは、DocBlockを配置する場所の例として機能します。
 */
class Foo
{
    /** @var string|null $title contains a title for the Foo */
    /** @var string|null $title Fooのタイトルが含まれています */
    protected $title = null;
 
    /**
     * Sets a single-line title.
     * 単一行のタイトルを設定します。
     *
     * @param string $title A text for the title.
     * @param string $title タイトルのテキスト
     *
     * @return void
     */
    public function setTitle($title)
    {
        // there should be no docblock here
        // ここには docblock があってはなりません
 
        $this->title = $title;
    }
}

本規約の範囲を超える使用例は、明示的にforeach内の変数をドキュメント化することです。いくつかのIDEではこの情報を使用して、オートコンプリート機能を支援します。

本規約ではこの特定の例をカバーしていません。なぜならforeachステートメントは 構造的要素 ではなく 制御フロー ステートメントと見なされるからです。

/** @var \Sqlite3 $sqlite */
foreach ($connections as $sqlite) {
    // there should be no docblock here
    // ここには docblock があってはなりません
    $sqlite->open('/my/database/path');
    <...>
}
  • 文字シーケンス /** で始まり、その後に空白文字が続き
  • */ で終わり
  • その間には0以上の行があります。

DocComment が複数の行にまたがる場合、すべての行はアスタリスク(*)で始まる必要があり(MUST)、これは開始行の最初のアスタリスクの位置に合わせる必要があります (SHOULD)。

単一行の例:

/** <...> */

複数行の例:

/**
 * <...>
 */

構造的要素 のタイプごとに次の表記法が使用できます。

  • 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. 基本原則


5. PHPDoc フォーマット

PHPDoc 形式には、次の ABNF定義があります。

PHPDoc             = [summary] [description] [tags]
summary            = *CHAR (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 )
tag-description    = 1*(CHAR / CRLF)
tag-signature      = "(" *tag-argument ")"
tag-argument       = *SP 1*CHAR [","] *SP

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

5.1. Summary

Summary には、構造的要素 の目的を定義する概要を含める必要があります (MUST)。概要は、1行または多くても2行でそれを超えないようにすることをお勧めします (RECOMMENDED)。

Summary は、PHPDoc の唯一のコンテンツでない限り、連続した2つの改行で終了する必要があります (MUST)。

Description が提供されている場合は、その前に Summary を付ける必要があります (MUST)。そうでないと、Description は最後に到達するまで、Summary と見なされるでしょう。

Summary は章のタイトルに相当するので、できるだけ少ないフォーマットを使用することは有益です。そのため、Description(次の章を参照)とは異なり、マークアップ言語をサポートするような推奨事項はありません。これをサポートするかどうかは、実装アプリケーションに明示的に委ねられます。


5.2. Description

Description はオプションです (OPTIONAL) が、このDocBlockに続く 構造的要素 が、Summary のみで説明できるよりも多くの操作 または より複雑な操作をが含んでいる場合は Description を含めるべきです (SHOULD)。

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

Description の一般的な用途はとりわけ次のとおりです:


5.3. Tags

タグは、後続の 構造的要素 に関する簡潔なメタデータを作成者が提供する方法を与えます。各タグは新しい行で始まり、その後にアットマーク(@)とタグ名が続き、その後に空白とメタデータ(説明を含む)が続きます。

メタデータが提供されている場合、それは複数行にまたがる場合があります(MAY)。そして、厳密な形式に従うことができ(COULD)、タグのタイプによって指定されるパラメーターを提供します。タグのタイプは、その名前から得ることができます。

例えば:

@param string $argument1 これはパラメータです。

上記のタグは、名前('param') と メタデータ('string $ argument1 これはパラメーターです。') で構成されています。メタデータは Type('string')、変数名('$argument') と 説明('これはパラメータです。')に分割されます。

タグの説明には、フォーマット言語として Markdown をサポートする必要があります(MUST)。Markdown の性質上、同じ行または後続の行でタグの説明を開始し、同じように解釈することができます。

従って、次のタグは意味的に同一です。

/**
 * @var string これは説明です。
 * @var string これは
 *    説明です。
 * @var string
 *    これは説明です。
 */

このバリエーションとしては、説明の代わりに、タグのシグニチャが使用されます。ほとんどの場合、タグは実際には アノテーション になります。タグ・シグネチャは、その操作に関するパラメータをアノテーションに与えることができます。

タグ・シグネチャが存在する場合、同じタグ内に説明が存在してはいけません (MUST NOT)。

タグによって提供されるメタデータにより、後続の 構造的要素 の実際の実行時の動作が変化する可能性があります。その場合、タグ の代わりに アノテーション という用語が一般的に使用されます。

5.3.1. タグ名

タグ名は、このタグによって表される情報のタイプを示します。また、それがアノテーションの場合は、後続の 構造的要素 に注入すべてき動作を示しています。

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

これらのタグまたはアノテーションは、次のいずれかによって名前空間を提供する必要があります (MUST)。

phpスタイルの名前空間がプレフィックスとして付いたタグ名の例:
(プレフィックスのスラッシュはオプションです)

上記の原文
Example of a tag name prefixed with a php-style namespace (the prefixing slash is OPTIONAL):

— 曖昧な翻訳 —
the prefixing slashとは何か?
@\Doctrine\Orm\Mapping\Entity()
:PHPDoc規約は、このドキュメントまたはその後の追加や拡張で指定されていない限り、タグの意味を想定していません。

つまり、プレフィックスの名前空間要素が提供されている限り、名前空間のエイリアスを使用することができます(CAN)。従って、以下も同様に合法です。

@Mapping\Entity()

独自のライブラリまたはアプリケーションが名前空間のエイリアスをチェックし、これからFQCN(完全修飾クラス名)を作成することがあるかもしれませんが、これはこの規約に影響を与えません。

重要:PHPDoc規約を使用するツールは、そのアプリケーションに登録されている名前空間を解釈して、カスタム動作を適用する場合があります(MAY)。

ベンダー名とハイフンが前に付いたタグ名の例:

@phpdoc-event transformer.transform.pre

ベンダーまたは名前空間のプレフィックスが付いていないタグ名は、タグカタログPSRや公式の付録に記載する必要があります (MUST)。

5.3.2. タグの特殊化

この規約で定義されたタグにニュアンスを与える方法を提供するために(ただし基本セットを拡張せずに)、タグ名の後にコロンを追加し、その後に、よりニュアンスのある説明を与える文字列を追加することにより、タグの特殊化を提供できます(MAY)。サポートされているタグ特殊化のリストは、時間の経過とともに変更される可能性があるため、タグカタログPSRではメンテナンスされません。タグカタログPSRのメタドキュメントには、タグ名ごとに一連の推奨事項が含まれている場合がありますが、プロジェクトは、該当する場合、独自のタグの特殊化を自由に選択できます。

重要:PHPDoc規約を使用するツールは、そのアプリケーションに登録/理解されているタグの特殊化を解釈してカスタム動作を適用することができますが(MAY)、タグカタログPSRで定義されている前述のタグ名を実装することを期待されているだけです。

例えば:

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

上記のタグは、名前('see')とタグの特殊化('unit-test')で構成されています。このように、これは開発が進行しているメソッドのユニットテストとの関係を定義します。

5.3.3. タグのシグニチャ

タグ・シグネチャは、現在のタグに固有の追加メタデータを提供するアノテーションためのに一般的に使用されます。

この提供されるメタデータは、所有するアノテーションの振る舞いに影響を与えるため、後続の 構造的要素 の振る舞いに影響を与える可能性があります。

シグネチャの内容は(タグ名で述べたように)タグタイプによって決定され、本仕様の範囲を超えます。ただし、タグ・シグネチャの後には、説明やその他の形式のメタデータを続けてはなりません(MUST NOT)。


5.4. 例

The following examples serve to illustrate the basic use of DocBlocks; it is advised to read through the list of tags in the Tag Catalog PSR.

次の例は、DocBlock の基本的な使用法を示しています。タグカタログPSRのタグのリストを一読することをお勧めします。

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

/**
 * This is a Summary.
 *
 * This is a Description. It may span multiple lines
 * or contain 'code' examples using the _Markdown_ markup language.
 * これは説明です。複数行にわたることができ、
 * _Markdown_マークアップ言語を使用した「コード」の例が含まれる場合があります。
 *
 * @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;


付録A. タイプ

ABNF

タイプには次のABNF定義があります。

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


詳細

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

タイプ が複数のタイプで構成されている場合、これらは共用体タイプ(union)の縦棒記号(|)または交差タイプ(intersection)のアンパサンド(&)のいずれかで区切る必要があります (MUST)。本仕様をサポートするインタープリターは、これを認識し、評価の前に タイプ を分割する必要があります (MUST)。

共用体タイプの例:

@return int|null

交差タイプの例:

@var \MyClass&\PHPUnit\Framework\MockObject\MockObject $myMockObject


配列

タイプ で表される値は配列にすることができます。このタイプは、次のオプションのいずれかの形式に従って定義する必要があります (MUST)。

  1. 指定されない場合: 表現された配列の内容の定義を与えない。

    例:
    @return array
  2. 単一のタイプを含んでいる指定: タイプ定義は、各配列値のタイプを読者に通知します。 その場合、与えられた配列の各値に対して1つのタイプのみが期待されます。

    例:
    @return int []

    mixed も単一のタイプであり、このキーワードを使用して、各配列の値に可能なタイプが含まれていることを示すことができる点に注意してください。

  3. 複数のタイプを含んでいる指定: タイプ定義は、各配列値のタイプを読者に通知します。 各値は、指定されたタイプのいずれかになります。

    @return(int | string)[]


有効なクラス名

有効なクラス名は、タイプが言及しているコンテキストに基づいて参照されます。従って、これは完全修飾クラス名(FQCN)であるか。または名前空間内に存在ローカル名であるかのいずれかになります。

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

上記の性質により、この情報を収集して形成するアプリケーションでは、クラスの各表現とともに子クラスのリストを表示することをお勧めします (RECOMMENDED)。 これにより、どのクラスがタイプとして受け入れられるかがユーザーに明らかになります。

上記の原文
Due to the above nature, it is RECOMMENDED for applications that collect and shape this information to show a list of child classes with each representation of the class. This would make it obvious for the user which classes are acceptable as type.

— 曖昧な翻訳 —
'applications that collect and shape this information' とはどんなアプリケーションなのか、PHPDocのツールと言う解釈でよいのか?


キーワード

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

注意:

これらのキーワードのほとんどは、PHPでクラス名として使用でき、実際のクラスと区別するのが難しい場合があります。そのため、ほとんどのクラス名は大文字の最初の文字で始まるため、キーワードは小文字にする必要があります (MUST)。コード内でこれらの名前のクラスを使用すべきではありません (SHOULD NOT)。
これらのキーワードの名前でクラスに名前を付けない理由は他にもありますが、それは本仕様の範囲を超えています。

このPSRによって認識されるキーワードは次の通りです:

  1. bool:このタイプが適用される要素の状態は TRUE または FALSE だけです。

  2. int: このタイプが適用される要素は、符号無し整数または符号付き整数です。

  3. float:このタイプが適用される要素は、実数です。

  4. string:このタイプが適用される要素は、2進文字列です。

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

  6. array:このタイプが適用される要素は値の配列です。

  7. iterable:この型が適用される要素は、PHPの定義による配列(array) または Traversable オブジェクトです。

  8. resource:このタイプが適用される要素は、PHPの定義によるリソースです。

  9. mixed:このタイプが適用される要素は、ここで指定された任意のタイプにすることができます。コンパイル時にどのタイプが使用されるかは不明です。

  10. void:このタイプは通常、メソッドまたは関数の戻り値のタイプを定義するときにのみ使用され、「何も返されない」ことを示します。したがって、ユーザーは戻り値に頼る頼るべきではありません。

    例1:
    /**
     * @return void
     */
    function outputHello()
    {
        echo 'Hello world';
    }

    上記の例では、returnステートメントが指定されていないため、戻り値は決定されません。

    例2:

    /**
     * @param bool $quiet when true 'Hello world' is echo-ed.
     *
     * @return void
     */
    function outputHello($quiet)
    {
        if ($quiet) {
            return;
        }
        echo 'Hello world';
    }

    この例では、関数には特定の値のないreturnステートメントが含まれています。実際の値が指定されていないため、これも void タイプと見なされます。

  11. null:このタイプが適用される要素は NULL 値であるか、さもなくば技術的には存在しません。

    voidとの大きな違いは、このタイプは、記述された要素がいつでも明示的な NULL 値を含む可能性があるあらゆる状況で使用されるということです。

    例1:

    /**
     * @return null
     */
    function foo()
    {
        echo 'Hello world';
        return null;
    }

    このタイプは通常、何も返されない可能性があることを示しますために、他のタイプと組み合わせて使用されます。

    例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;
    }
  12. callable:このタイプが適用される要素は、関数呼び出しへのポインターです。これは、PHPの定義による呼び出し可能(callable)な任意のタイプです。

  13. self:この型が適用される要素は、ドキュメント化された要素がもともと含まれていたのと同じクラスです。

    例:

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

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

    例(前の例の状況が引き続き適用されます):

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

    この状況では、self がクラス A または B のいづれかとして解釈されるため、あいまいさが生じる可能性があります。これらの場合、self は、self タイプを含む DocBlock が記述されているクラスのインスタンスであると解釈しなければなりません (MUST)。

    上記の例で、self はクラス A のメソッド c で定義されているため、常にクラスAを参照する必要があります(self)。

    上記の性質により、この情報を収集し形成化するアプリケーションでは、クラスの各表現とともに子クラスのリストを表示することをお勧めします (RECOMMENDED)。 これにより、どのクラスが型として受け入れられるかがユーザーに明らかになります。
  14. static:この型が適用される要素は、ドキュメント化された要素が含まれているのと同じクラスであるか、またはサブクラスで見つかった場合、元のクラスではなくそのサブクラスの型です。

    このキーワードは、PHPで定義されている(静的メソッドやプロパティ、または変数修飾子でもない)遅延静的束縛(Late Static Bindings)に対するキーワードと同じように動作します。

  15. $this:このタイプが適用される要素は、与えられたコンテキストの現在のクラスとまったく同じインスタンスです。そのため、返されるインスタンスは同じクラスだけでなく同じインスタンスでなければならないので、このタイプは static のより厳密なバージョンという事になります。

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