Стандарты API документации и комментариев

На данной странице описаны стандарты, покрывающие написание комментариев к коду, а также, как документировать его API.

Заметки и стандарты

Общие соображения по разбору модулем API

Модуль API парсит как документацию, так и сам код PHP файлов. Ожидается что они будут в едином формате, который похож на PHPDoc, JavaDoc и т.д. Изначально документация базировалась на Doxygen, но затем переросла его и появились свои собственные теги, а также специфичный для Drupal функционал.

Модуль API парсит документацию, которая находится в специальных документационных блоках (также известных как "docblocks").

Пример синтаксиса docblock:

/**
 * Sample summary line.
 *
 * Next paragraph. Etc.
 */
(code being documented goes here, such as a function declaration, class, etc.)

Общие заметки касаемо модуля API и документации, которую он будет парсить:

  • Модуль API считает следующие расширения файлов, как расширения PHP: .php, .module, .inc, .install, .engine, .theme, .profile и .test.
  • Когда парсится PHP файл, модуль API парсит как документацию, так и непосредственно PHP код. PHP файлы с синтаксическими ошибками, могут привести к проблемам.
  • Документация распознается только по специальным PHP комментариям, которые начинаются с /**.
  • Одностроковые комментарии внутри кода, начинающиеся с // и комментарии начинающиеся с /* не распознаются как docblock.
  • Документационные блоки обычно имеют * в начали каждой линии, которые модуль API срезает при формировании документации.
  • Для разделения абзацев используется пустая строка. Некоторые теги также вызывают принудительное завершение параграфа: @param, @return, @see, @var. Модуль API не понимает документацию, если она состоит только из одиночного тега, например @param.
  • Модуль API не беспокоится о длине строки комментария, тем не менее, Drupal стандарты имеют жесткие требования на данный счёт.
  • Первый абзац документационного блока также известен как сводка.
  • Для того чтобы задокументировать функцию, класс и т.д., документационный блок должен находиться прямо перед началом структуры, без пустых линий между ними. В стандарте также имеются несколько документационных блоков, которые "сами по себе".
  • Модуль API автоматически превращает в ссылки все распознанные функции, классы и т.д.

Общие стандарты документирования API

В данном разделе собраны заметки и стандарты относительно всех документационных блоков.

Пример:

/**
 * Sample summary line.
 *
 * Next paragraph. Etc.
 */
(code being documented goes here, such as a function declaration, class, etc.)
  • Вся документация и комментарии должны быть в соответствующей форме, использовать правильную грамматику и пунктуацию, а также следовать общим указаниям на счёт содержимого drupal.org: https://drupal.org/style-guide/content.
  • Добавляйте пробел между символами комментария (* или //) и первым символом предложения.
  • Документация должна отражать актуальную версию кода, а не отличия от предыдущей или планы на будущую (за исключением @todo и @deprecated тегов).
  • Предложения должны быть разделены одиночным пробелом.
  • Комментарии и названия переменных должны быть на английском языке, а также использовать правописание английского языка США, а не Великобритании (например, "color", а не "colour").
  • Для того чтобы сослаться на тему или модуль, используйте формулировку и заглавные буквы, например "the Foo Bar module".
  • Капсом разрешено описывать только константы, например TRUE.
  • Документационные блоки должны иметь * в начале каждой линии.
  • Линии содержащие комментарии, включая документационные блоки, должны быть как можно ближе к 80 символам, но не длиннее данного значения. Есть несколько исключений, они будут описаны отдельно.
  • Линии после тегов, таких как @param, @return и т.д., должны содержать документацию под данным тегом, а также дополнительно быть сдвинуты двумя пробелами.
  • Каждая функция, константа, класс, интерфейс, а также составные класса (методы, свойства, константы), как и сам файл, должны быть задокументированы, даже те, что являются приватными.
  • Все сводки (первая линия документационного блока) должны быть короче 80 символов, начинаться с заглавной буквы и заканчиваться точкой (.). Они должны предоставлять краткое описание, что делает функция, что делает класс, что содержит файл и т.д.
  • Когда вы реализуете хук, используйте краткую сводку в формате "Implements hook_name().". В данном случае, опустите описание параметров, возвращаемого значения и функции.

Стандарты комментирования внутри кода

Настоятельно рекомендуется писать комментарии к коду по мере его написания. Общее правило заключается в том, что если вы смотрите на часть кода и думаете "Ничего себе, прокомментирую позже.", вы должны прокомментировать данный код сейчас, пока вы помните как он работает. Комментарии должны быть непосредственно над кодом, который они комментируют. Например:

// Disable recording of cached pages.
\Drupal::service('page_cache_kill_switch')->trigger();

Если каждому элементу списка необходимо добавить отдельный комментарий, то комментарии могут быть на той же линии что и элемент списка, и быть отформатированными с отступом до комментария. Но лучше всего, разделяйте комментарии и элементы списка, как в данном примере:

$defaults = [
// (required) The name of the route this task links to.
'route_name' => '',
// Parameters for route variables when generating a link.
'route_parameters' => [],
// The static title for the local task.
'title' => '',
];

C-подобные комментарии (/* */) и стандартные комментарии C++ (//) допускаются, тем не менее, лучше используйте //, даже для многострочных комментариев (повторяя // для каждой строки). Использование комментариев в Perl\shell\YAML формате (#) для PHP кода не рекомендуется.

@todo тег должен следовать тем же правилам форматирования, что и для документационных блоков (дополнительные два пробела для второй и последующих строк). Пример:

// Some other comment here.
// @todo Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
//   diam nonumy eirmod tempor invidunt ut labore et dolore magna
//   aliquyam erat, sed diam voluptua.
// We explicitly delete all comments.
comment_delete($cid);

Стандарты документирования API для функций

Документирование функций, в какой-то степени, более сложный процесс, чем документирование других структур в PHP, поэтому они имеют свои собственные стандарты:

  • Каждый параметр функции должен быть задокументирован используя тег @param. Кроме исключений описанных ниже.
  • Если функция возвращает значение, оно должно быть задокументировано используя тег @return. Кроме исключений описанных ниже.
  • Для большинства функций (кроме исключений ниже), сводка должна начинаться с глагола настоящего времени, в третьем лице и единственном числе, объясняя при этом, что делает функция. Например "Calculates the maximum weight for a list." (Рассчитывает максимальный вес для списка.).
  • Функции, чью задачу легко описать в сводке, могут содержать только строку со сводкой (игнорируя описание параметров и возвращаемого значения).

В дополнение к этому, также имеются стандарты по документированию особых типов функций:

Описание хука

Описание или определение хука — документирования конкретного хука, который объявлен текущим модулем.

Сводка должна начинаться с императивного глагола, который описывает, зачем другим модулям может пригодиться данный хук. Например: "Отвечает при удалении содержимого.". Определения хуков помещаются в файлах .api.php, которые не используются Drupal напрямую.

Описание каждого конкретного хука состоит из фиктивной функции начинающейся с hook, а тело функции показывает пример использования данного хука. Все параметры и возвращаемые значения должны быть задокументированы.

Пример:

/**
 * The user just logged in.
 *
 * @param \Drupal\user\UserInterface $account
 *   The user object on which the operation was just performed.
 */
function hook_user_login(UserInterface $account) {
  $config = \Drupal::config('system.date');
  // If the user has a NULL time zone, notify them to set a time zone.
  if (!$account->getTimezone() && $config->get('timezone.user.configurable') && $config->get('timezone.user.warn')) {
    \Drupal::messenger()
      ->addStatus(t('Configure your <a href=":user-edit">account time zone setting</a>.', [
        ':user-edit' => $account->toUrl('edit-form', [
          'query' => \Drupal::destination()
            ->getAsArray(),
          'fragment' => 'edit-timezone',
        ])->toString(),
      ]));
  }
}

Реализация хука

Реализация хука — использование существующего хука в своём модуле.

Документирование таких функций используют короткий формат сводки.

/**
 * Implements hook_help().
 */
function blog_help($section) {

При необходимости вы можете указать дополнительные детали, относящиеся к реализации конкретного хука отдельным абзацем после сводки.

Не документируйте параметры и возвращаемые значения, а также что делает хук (если это не относится к конкретно вашему варианту реализации хука), всё это находится в описании хука.

Если хук содержит динамический кусок для подстановки, необходимо указать, для чего данная подстановка будет использована.

/**
 * Implements hook_form_FORM_ID_alter() for node_type_form.
 */
function mymodule_form_node_type_form_alter(&$form, &$form_state) {

Функции обновления

К функциям обновления относятся реализации хуков hook_update_N() и hook_post_update_NAME().

Данные хуки обрабатываются особенным способом. Сводка данного хука (первая строка комментария) будет отображена пользователю как описание ожидающего обновления при запуске update.php. Она должна описывать какие задачи решает данное обновление.

При необходимости, дополнительное описание может идти со второго абзаца.

/**
 * Add several fields to the {node_revision} table.
 *
 * Longer description can go here, if necessary.
 */
function module_name_update_8701() {

Обратите внимание что сводка должна начинаться с повелительного глагола.

Функции обратного вызова для функций PHP

Многие функции PHP, такие как uasort() и т.д., требует передачи функции обратного вызова. Когда вы документируете функцию, которая предназначена для использования в качестве функции обратного вызова, прежде всего, начните со стандартной сводки. После сводки, вы должны обозначить что данная функция предназначена для подобного использования, а также, какая функция, или список функций, Drupal, используют её.

Например:

/**
 * [standard first line]
 *
 * Callback for uasort() within system_themes_page().

Функция обратного вызова и реализации

Как и стандартные функции PHP, Drupal API иногда требует функции обратного вызова для своей работы. В данном контексте, "функция обратного вызова" — функция, которую необходимо объявить в модуле с реализацией какого-то хука, например: создание пакетной обработки, плагинов или другого функционала Drupal.

Для того чтобы задокументировать параметры и возвращаемое значение для функции обратного вызова, создайте описание функции в качестве примера с документационным блоком в *.api.php файле модуля. Также как это делается для хуков, предоставляемых модулем. Затем, в хуке или любом другом месте, который опирается на данное поведение, укажите название данной функции.

  • Описание функций обратного вызова в *.api.php файле должно начинаться с "callback_" префикса, с понятным названием, описывающим назначение.
  • Тело данной функции должно быть примером реализации подобной функции обратного вызова.
  • Сводка в комментарии должна описывать что делает функция обратного вызова. Описание должно начинаться с императивного глагола, который объясняет, почему модуль описывает данную функцию обратного вызова.
  • Далее, должна идти строк начинающаяся с "Callback for ___.", где __ — название хука, функции или другого компонента, для которого она написана.
  • Данные функции должны быть добавлены в собственную группу "@ingroup callbacks".
  • Хуки или иные функции, использующие данную функцию обратного вызова, должны ссылаться на её название в документации.
  • Реализации функции обратного вызова должны иметь лишь информацию о реализации, ссылающуюся на данную документацию: "Implements callback_NAME().".

Пример:

// In *.api.php file:

/**
 * Perform tasks when a batch is complete.
 *
 * Callback for batch_set().
 *
 * @param bool $success
 *   A boolean indicating whether the batch operation successfully concluded.
 * @param int $results
 *   The results from the batch process.
 * @param array $operations
 *   The batch operations that remained unprocessed. Only relevant if $success
 *   is FALSE.
 *
 * @ingroup callbacks
 */
function callback_batch_finished($success, $results, $operations) {
  // Sample code here.
}

// Documentation for batch_set():

 *   - finished: Name of an implementation of callback_batch_finished(). This is
 *     executed after the batch has
 *     completed. This should be used to perform any result massaging that may
 *     be needed, and possibly save data in $_SESSION for display after final
 *     page redirection.

// Note: especially in Drupal 8, these callback implementations may be
// class methods rather than functions, which are passed in as PHP
// callables rather than strings. So an alternate wording that
// implies that this is also acceptable would be:

 *   - finished: A callable that implements callback_batch_finished().

// Actual callback: _node_mass_update_batch_finished() function.

/**
 * Implements callback_batch_finished().
 */
function _node_mass_update_batch_finished($success, $results, $operations) {
  // …
}

Функции предварительной обработки шаблонов

Функции предварительной обработки шаблонов (preprocess), документируются используя следующие стандарты:

  • Первая строка должна быть "Prepares variables for [description] templates.".
  • Вторая строка должна содержать название файла шаблона по умолчанию: "Default template: foo-bar.html.twig.".
  • Все составные переменной $variables должны быть задокументированы.

Пример:

/**
 * Prepares variables for container templates.
 *
 * Default template: container.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - element: An associative array containing the properties of the element.
 *     Properties used: #id, #attributes, #children.
 */
function template_preprocess_container(&$variables) {

Стандарты документирования Drupal API для классов и пространств имён

Следующие стандарты применяются при документировании классов и использующих пространства имён в Drupal API документации:

  • Все классы и все их методы (включая приватные методы) должны быть задокументированы.
  • Если класс имеет метод, который переопределяет метод от родительского класса или интерфейса, при этом, их документация подходит, используйте короткую запись:
/**
 * {@inheritdoc}
 */
public function …
  • Используйте глагол третьего лица, чтобы написать сводку для класса, интерфейса или метода. Например: "Represents a ..." or "Provides ...".
  • Задокументируйте исключения используя @throws.
  • Если вы используете пространство имён в документации, убедитесь что оно всегда указано полное пространство имён (начинается с обратного слэша).
  • Сразу после @tag (@param, @return, @var и т.д.), имена классов и интерфейсов должны содержать полное пространство имён.
  • Прочие Drupal стандарты, касаемые пространства имён ещё в процессе обсуждения и окончательные решения по ним не приняты.

Порядок секций в документации

Документационные блоки для функций, классов и прочих PHP структур описываются в следующем порядке для соответствия Drupal стандартам. Разделы, которые не требуются, можно пропускать. Секции различного типа разделяются пустой строкой.

Порядок секций:

  • Комментарий-сводка, заканчивающийся точкой.
  • Дополнительные абзацы с объяснениями.
  • @var
  • @param
  • @return
  • @throws
  • @ingroup
  • @deprecated
  • @see
  • @todo
  • @Plugin и прочие аннотации.

Создание списков в документации

Списки в документации начинаются с -.

Пример синтаксиса:

 * Lists are usually preceded by a line ending in a colon:
 * - Item in the list.
 * - Another item.
 *   - key: Sub-list with keys, first item.
 *   - key2: (optional) Second item with a key.
 * - Back to the outer list. Sometimes list items are quite long, in which case
 *   you can wrap the text like this.
 * - Last item in the outer list.
 * Text that is outside of the list continues here.

Примечания по синтаксису:

  • Дефис в качестве первого символа в строке (за исключением *) указывает на элемент списка.
  • Все пункты списка одного уровня, должны иметь идентичные отступы.
  • Между пунктами не должно быть пустых линий, если они принадлежат одному списку.
  • Если в списке требуются ключи, используйте двоеточие между ключом и его описанием. API модуль отформатирует ключи при помощи <strong>.

Примечания по Drupal стандартам:

  • Строка перед списком должна заканчиваться двоеточием :.
  • Дефис выравнивается по тексту, содержащий этот уровень списка, это означает, что каждый каждый уровень вложенности отступает на два пробела.
  • Ключи массива не помещаются в кавычки; ключи, которые описывают строки (например значения параметров), должны быть помещены в кавычки.
  • Помечайте необязательные элементы списки при помощи (optional), а значения по умолчанию при помощи (default).

Типы данных в документации

Указывайте типы данных в документации (@param, @return и т.д.).

Примеры:

int
string|bool
\Drupal\Core\Database\StatementInterface
int[]
\Drupal\node\NodeInterface[]
$this
static

Примечания к синтаксису:

  • Типы данных могут быть примитивные (int, string, и т.д.), сложные встроенные PHP типы (array, object, resource) или PHP классы.
  • Если доступен единственный тип, используйте только его.
  • Если доступно несколько возможных типов, разделяйте их вертикальной чертой (|).
  • Для массивов, содержание которых состоит из одинаковых классов или объектов, указывается полное пространство имён до класса или интерфейса с [] на конце.
  • Массивы состоящие из встроенных PHP типов описываются с [] на конце.
  • Когда вы возвращаете основной объект класса ($this), используйте @return $this.
  • Когда создаете новый экземпляр текущего класса, используйте @return static.

Примечания по Drupal стандартам:

  • Используйте имена интерфейсов там где это возможно, или максимально общий класс, вместо конкретного класса.
  • Всегда используйте полное пространство имён (начинаются с обратного слэша) для классов и интерфейсов.
  • Вы можете опустить описание для @return $this и @return static.
  • Для встроенных в PHP типов используйте следующие имена:
    • array (НЕ Array). Тем не менее, синтаксис [] приоритетнее, если это допустимо. То есть, если вы знаете что содержит массив и все его элементы данного типа, то указывайте string[] или \My\Class\Name[] и т.д., вместо использования общего типа array.
    • bool (НЕ boolean или Boolean). Если доступно только значение TRUE или FALSE, тогда указывайте true или false вместо вариантивного типа.
    • false (НЕ FALSE)
    • float
    • int (НЕ integer)
    • null (НЕ NULL);
    • object (НЕ stdClass)
    • resource
    • string
    • true (НЕ TRUE)

@TODO complete it @TODO create separete page for https://www.drupal.org/node/1823416

Ссылки

Помогите нам сделать документацию лучше!

Вся документация Druki с отрытым исходным кодом. Нашли ошибку или неточность? Создайте pull request.

Редактировать текущий документ Обсудить улучшение

Или узнайте как контрибутить.