Комментирование кода по правилам PHPDoc

7 марта 2016
PHPDoc – это устоявшийся стандарт комментирования PHP-кода. На основе комментариев с помощью программы phpDocumentor (https://www.phpdoc.org/) можно автоматически сформировать документацию. Для разработчика важность не столько в документации, сколько в расширенном и стандартизированном пояснении кода.

Введение

Комментирование по правилам PHPDoc выполняется в специальных док-блоках, которые начинаются с символов /** и заканчиваются символами */

Пример многострочного док-блока:
/**
 * Выполняет сканирование файлов на наличие обфускаций
 *
 * @param int Путь к папке относительно корня сайта
 * @return array Вернёт массив с именами файлов, в которых есть обфускации 
 */

Пример однострочного док-блока:
/** Отправка писем выполняется через внешний SMTP-сервер  */

Комментариями через док-блоки описываются все ключевые сущности кода: файл скрипта, функции, классы (включая интерфейсы и трейты), свойства, методы, важные участки кода. Не нужно стесняться комментировать даже то, что сейчас кажется очевидным – через два месяца разработчик, возможно, не вспомнит, что этот код был его и станет задаваться вопросом: «Кто и для чего сделал эту непонятную хрень?». 

В комментариях можно указывать специальные теги (их ещё называют дескрипторами), которые размечают функциональность. Например, можно указать аргументы функций, их типы и назначение. В примере выше аргумент функции описывается через тег @param. Кроме того, можно указать автора @author, версию @version, ссылки на внешние ресурсы @link и другую информацию.


Теги

@api

Синтаксис: @api
Тег @api применяется к общедоступным элементам, чтобы выделить их в сгенерированной документации, указывая пользователю на общедоступные компоненты (функции, методы) API.

Когда используется тег @api, другие структурные элементы с публичной (public) видимостью служат для поддержки внутренней структуры и не рекомендуются к использованию пользователями API.
Пример:
<?php

class UserService
{
    /**
     * Возвращает информацию о текущем пользователе
     *
     * @api
     */
    public function getUser()
    {
        /*...*/
    }
}

@author

Синтаксис: @author [имя автора] [<адрес email>]
Тег @author используется для указания авторства элемента кода. Элементы, помеченные тегом @author, в документации будут отображать заголовок автора.

Пример:
/**
 * @author Сергей Иванов
 * @author Ольга Овчинникова <olga.ovh@example.ru>
 */

@copyright

Синтаксис: @copyright [описание авторских прав]
Тег @copyright используется для указание того человека или юридического лица, кому принадлежат авторские права на структурный элемент.

Пример:
/**
 * @copyright 1997-2016 ООО «Тест-PHP»
 */

@deprecated

Синтаксис: @deprecated [Версия, с которой элемент считается устаревшим] [описание]
Тег @deprecated используется для указания того, что структурный элемент являются устаревшим и будет удалён в следующих версиях. Структурные элементы, помеченные тегом @deprecated, в документации будут перечислены в отчете об устаревших элементах и их названия будут показаны как зачеркнутые.

Если связанный элемент (например, функция) заменен другим, то рекомендуется добавить тег @see, указывающий на новый элемент.

Пример:
/**
 * Возвращает полное количество игроков
 *
 * @return int
 *
 * @deprecated 2.0.0 Больше не используется
 * @see Game::getPlayers()
 */
private function getCount()
{
    /* ... */
}

@see

Синтаксис: @see [URI или FQSEN] [описание]
Тег @copyright используется для указание связанного элемента или url-адреса. Тег @see ДОЛЖЕН содержать описание, предоставляющее дополнительную информацию о взаимосвязи между элементом и его целью.

В описании использовано сокращение FQSEN. «FQSEN» расшифровывается как «Fully Qualified Structural Element Name» (Полное наименование структурного элемента). Для каждого типа «Структурного элемента» могут использоваться следующие обозначения (указываются сразу примеры):
  • Пространство имён: \My\Space
  • Функция: \My\Space\myFunction()
  • Константа: \My\Space\MY_CONSTANT
  • Класс: \My\Space\MyClass
  • Интерфейс: \My\Space\MyInterface
  • Трейт: \My\Space\MyTrait
  • Метод: \My\Space\MyClass::myMethod()
  • Свойство: \My\Space\MyClass::$my_property
  • Константа внутри класса: \My\Space\MyClass::MY_CONSTANT

Примеры использования @see:
/**
 * @see number_of() Синоним
 * @see MyClass::$items Хранит набор записей, просмотренных пользователем
 * @see https://example.com/my/bar  Документация по использованию
 *
 * @return int Возвращает количество записей
 */
function count()
{
    /* ... */
}

@filesource

Синтаксис: @filesource
Тег @filesource указывает генератору документации phpDocumentor включить исходный код текущего файла в документацию. Тег указывается в начале файла.

Пример:
<?php
/**
 * @filesource
 */

@ignore

Синтаксис: @ignore [описание]
Тег @ignore указывает генератору документации phpDocumentor, что помеченный элемент не должен обрабатываться (то есть должен игнорироваться). 

РЕКОМЕНДУЕТСЯ добавлять описание, почему элемент следует игнорировать.

Пример:
if ($ostest) {
    /**
     * Константа будет либо 'Unix', либо 'Windows'
     */
    define("RUNTIME_OS","Unix");
} else {
    /**
     * @ignore Выше добавлено пояснение, поэтому не дублируем описание консанты
     */
    define("RUNTIME_OS","Windows");
}

@internal

Синтаксис: @internal [описание]
Тег @internal используется для обозначения того, что структурный элемент является внутренними для приложения, библиотеки или пакета. Элементы, помеченные тегом @internal, будут отфильтрованы при создании документации, если не используется аргумент командной строки --parseprivate.

Пример:
/**
 * @internal
 * Возвращает общее количество игроков
 * @return int
 */
public function count()
{
    /* ... */
}

@license

Синтаксис: @license [url с лицензией] [название лицензии]
Тег @internal используется для указания лицензии, применяемой к структурному элементу.

РЕКОМЕНДУЕТСЯ применять теги @license ТОЛЬКО к файлам, чтобы избежать путаницы в отношении того, какая лицензия применяется к какому-либо конкретному структурному элементу.

Для каждой применимой лицензии должен быть один тег @license.

При создании документации элементы, помеченные тегом @license, будут содержать ссылку на лицензию, если указан URL-адрес или указано одно из следующих названий лицензии:
  • GPL, или GNU General Public License, версия 2
  • GPL, или GNU General Public License, версия 3
  • LGPL, или GNU (Library|Lesser) General Public License, версия 3
  • BSD
  • FreeBSD
  • MIT

Пример:
<?php
/**
 * @license GPL
 *
 * @license https://opensource.org/licenses/gpl-license.php GNU Public License
 */

@link

Синтаксис: @link [URI] [описание]
Тег @link указывает пользователю на связь между структурным элементом и страницей, указанной в URI.

Пример:
/**
 * Возвращает общее количество записей
 * @link https://example.com/my/count Документация по использованию функции
 *
 * @return int 
 */
function count()
{
    /* ... */
}

@method

Синтаксис: @method [[static] return type] [name]([[type] [parameter]<, ...>]) [описание]
Тег @method используется в ситуациях, когда класс содержит метод __call() или __callStatic() и описывает какие не явные (магические) методы класса можно вызвать.. Тег НЕ ДОЛЖЕН использоваться, если он не связан с классом или интерфейсом. 

В документации структурные элементы типа class или interface, помеченные тегом @method, покажут дополнительные методы в своем списке методов, исходя из данных, описанных этим тегом.

Пример:
class Parent
{
    public function __call()
    {
        /* ... */
    }
}

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

@package

Синтаксис: @package [раздел уровня 1]\[раздел уровня 2]\[раздел уровня N]
Тег @package используется для классификации структурных элементов по логическим подразделениям.

Каждый уровень в логической иерархии ДОЛЖЕН быть разделен обратной косой чертой \, чтобы быть знакомым пространствам имен. Иерархия МОЖЕТ иметь бесконечную глубину, но рекомендуется, чтобы глубина была меньше или равна шести уровням.

В документации структурные элементы, помеченные тегом @package, группируются и упорядочиваются в отдельном разделе боковой панели.

Пример:
/**
 * @package PSR\Documentation\API
 */

@param

Синтаксис: @param [тип переменной] [имя переменной] [описание переменной]
Тег @param используется для документирования аргументов функции или метода.

Описание НЕ ОБЯЗАТЕЛЬНО, но РЕКОМЕНДУЕТСЯ, например, в случае сложных структур, таких как ассоциативные массивы. 

Тег @param МОЖЕТ содержать многострочное описание и не нуждается в явном разделении. Тег НЕ ДОЛЖЕН встречаться более одного раза для каждого аргумента и ограничен структурными элементами типа «метод» и «функция».

Пример:
/**
 * Подсчитывает количество элементов в массиве
 *
 * @param mixed[] $items Массив элементов
 * @param bool $recursive Учитывать ли при подсчётах внутренние массивы, 
 *                           находящиеся в элемента.
 *                           По умолчанию используется значение ‘false’.
 *
 * @return int Вернёт количество элементов
 */
function count(array $items, bool $recursive = false)
{
    /* ... */
}

@property, @property-read, @property-write

Синтаксис: @property[-read|-write] [тип свойства] [название свойства] [описание]
Теги @property, @property-read, @property-write используются, когда класс или трейт использует методы __get() или __set() для динамических свойств.

Варианты @property-read и @property-write МОГУТ использоваться для указания магических свойств, которые могут быть только прочитаны или записаны.

В документации структурные элементы типа class или trait, помеченные тегом @property, @property-read и @property-write, будут отображать дополнительное свойство в своем списке свойств, исходя из указанных в тегах данных.

Пример:
class Parent
{
    public function __get()
    {
        /* ... */
    }

    public function __set()
    {
        /* ... */
    }
}

/**
 * @property string $myProperty
 * @property-read string $myReadOnlyProperty
 * @property-write string $myWriteOnlyProperty
 */
class Child extends Parent
{
    /* ... */
}

@return

Синтаксис: @return [тип возвращаемого результата] [описание]
Тег @return используется для указания возвращаемого значения функции или метода.

Тег МОЖЕТ содержать многострочное описание и не нуждается в явном разделении.

Рекомендуется использовать этот тег с каждой функцией и методом. Исключениями МОГУТ служить:
  • конструкторы, тег @return здесь может быть опущен, и в этом случае подразумевается @return self.
  • функции и методы без возвращаемого значения, тег @return здесь может быть опущен, и в этом случае подразумевается @return void.

Пример:
/**
 * Подсчитывает количество элементов в массиве
 *
 * @return int Вернёт количество элементов
 */
public function count()
{
    /* ... */
}

@since

Синтаксис: @since [версия] [описание]
Тег @since используется для указания версии, с которой был добавлен или изменён структурный элемент.

РЕКОМЕНДУЕТСЯ, чтобы версия соответствовала семантическому номеру версии (x.x.x) и могла содержать описание для предоставления дополнительной информации.

Тег @since НЕ ДОЛЖЕН использоваться для отображения текущей версии элемента, для этой цели используется тег @version.

Тег может встречаться несколько раз в рамках одного док-блока . В таком случае при формировании документации каждое появление тега @since обрабатывается как запись в журнале изменений. РЕКОМЕНДУЕТСЯ добавлять описание для каждого такого тега.

Пример:
/**
 * Подсчитывает количество активных (не заблокированных) игроков
 *
 * @return int Вернёт количество элементов
 * 
 * @version 1.0.5
 * @since 1.0.2 Учитываются только активные игроки
 * @since 1.0.1 Оптимизирован алгоритм подсчёта.
 * @since 1.0.0 Функция была создана.
 */
public function count()
{
    /* ... */
}

@source

Синтаксис: @source [номер начальной строки [количество строк]] [описание]
Тег @source используется для передачи исходного кода структурного элемента элемента в документацию. 

Если указаны номера строк (начальной и количество), то в документацию передаётся не весь код структурного элемента, а только код в рамках указанных строк. Если начальная строка не указана, то исходный код структурного элемента передаётся полностью. Если количество строк не указано, то передаётся код до конца структурного элемента (то есть до конечной фигурной скобки).

РЕКОМЕНДУЕТСЯ (но не обязательно) указывать описание для более подробного объяснения представленного кода.

Пример:
/**
 * Подсчитывает количество активных (не заблокированных) игроков
 *
 * @return int Вернёт количество элементов
 * 
 * @source 2 1 Проверка на заполнение свойства с количеством элементов
 */
public function count()
{
    if (null === $this->count) {
        /* ... */
    }
}

@throws

Синтаксис: @throws [тип возвращаемой ошибки] [описание]
Тег @throws используется для указани, что структурный элемент выдаёт определенный тип ошибки (исключения).

Тип ошибки, ДОЛЖЕН представлять объект, реализующий интерфейс Throwable (https://www.php.net/manual/ru/class.throwable.php), такой как Error, Exception или любой их подкласс.

РЕКОМЕНДУЕТСЯ предоставлять описание, описывающее причину возникновения исключения. Также РЕКОМЕНДУЕТСЯ использовать этот тег для каждого случая возникновения исключения, даже если оно имеет один и тот же тип. 

Пример:
/**
 * Подсчитывает количество элементов в предоставленном массиве
 *
 * @param mixed[] $array Массив элементов
 *
 * @throws InvalidArgumentException Вернёт ошибку, если аргумент 
 *                                                                   функции не является массивом
 *
 * @return int Возвращает количество элементов
 */
function count($items)
{
    /* ... */
}

@todo

Синтаксис: @todo [описание]
Тег @todo используется для указания будущих намерений и задач, связанных с текущим структурным элементом.

Если указаны номера строк (начальной и количество), то в документацию передаётся не весь код структурного элемента, а только код в рамках указанных строк. Если начальная строка не указана, то исходный код структурного элемента передаётся полностью. Если количество строк не указано, то передаётся код до конца структурного элемента (то есть до конечной фигурной скобки).

РЕКОМЕНДУЕТСЯ (но не обязательно) указывать описание для более подробного объяснения представленного кода.

Пример:
/**
 * Подсчитывает количество элементов в предоставленном массиве
 *
 * @param mixed[] $array Массив элементов
 *
 * @throws InvalidArgumentException Вернёт ошибку, если аргумент 
 *                                                                   функции не является массивом
 *
 * @return int Возвращает количество элементов
 * 
 * @todo Добавить второй аргумент-флаг для подсчёта только
 *              положительных значений
 */
function count($items)
{
    /* ... */
}

@uses

Синтаксис: @uses [FQSEN] [описание]
Тег @uses используется указания двусторонней ссылки между текущим элементом и указанным в FQSEN. Что такое FQSEN смотрите выше.

Тег @uses отличается от @see тем, что @see является односторонней ссылкой.

Пример:
/**
 * Подсчитывает и возвращает количество игроков
 * 
 * @return int
 * 
 * @uses MyClass::$players Использует, для подсчёта количества
 */
public function countPlayers()
{
    /* ... */
}

@var

Синтаксис: @var [тип данных] [имя элемента] [описание]
Тег @var используется для описания переменных, констант и свойств.

Пример:
/** @var int $int Счётчик */
$int = 0;

$int++;

class Document
{
    /**
     * @var int INDENT Размер отступа в пробелах (шт)
     */
    const INDENT = 4;

    /** @var string|null Описание документа */
    protected $description = null;

    /* ... */
}