Если вы когда-либо работали с чьим-либо кодом, вы знаете боль (или удовольствие) отсутствующей (или существующей) документации. Хорошо документированный код является одним из краеугольных камней профессиональной разработки программного обеспечения, и если вы не научитесь документировать свой код, чтобы он стал второй натурой, вы наносите себе и другим больше вреда, чем пользы.
Если это звучит слишком обескураживающе, это потому, что так и должно быть. Если вы пишете недокументированный код, вам следует прекратить этот момент. Я серьезно. Отбросьте все, сохраните и выйдите, и сосредоточьтесь на улучшении этой важной части вашего рабочего процесса.
На протяжении многих лет мне приходилось мучиться с ужасной документацией (привет, Zend Framework!), А также пролистывать довольно солидные вещи (спасибо, Swift Mailer!). Я пытаюсь документировать каждый файл, который я создаю, и я делал это достаточно долго, теперь это стало второй натурой. У меня есть строгий стандарт документации, которому я следую, тот, который совместим с ApiGen, генератором документации, и который хорошо читается человеком, но также полностью совместим с современными IDE. Это означает, что я могу сгенерировать свою библиотечную документацию для общественности вместе с примерами, учебными пособиями, описаниями и возможными ошибками с помощью одной команды.
ApiGen — это анализатор док-блоков, такой как PhpDocumentor. PhpDocumentor существует намного дольше, чем ApiGen, но, к сожалению, его разработка несколько затормозилась и ему не хватает современной документации и примеров. Он также имеет некоторые неприятные зависимости, которые могут вызвать проблемы на новых установках PHP, и часто выдает ошибки, которые нигде не документированы. Вы можете узнать больше о PhpDocumentor в предыдущей статье SitePoint . Что касается того, что лучше … Я считаю, что ApiGen будет логичным выбором из-за следующих недостатков PhpDocumentor:
- требуется докблок на уровне страницы (над пространствами имен)
это не имеет смысла; они никогда не анализируются должным образом, и введенные описания нигде не найдены, Обновление, 24 августа 2012: комментатор указал, что блоки на уровне страницы фактически используются в шаблонах, отличных от стандартных. Однако они все еще не являются необходимыми и генерируют ошибки при разборе PhpDoc, оставаясь в документации как зарегистрированные ошибки на неопределенное время. - нет поиска в сгенерированной документации.
ошибки компоновки — длинные имена пакетов нарушают раскрывающееся меню «Api Documentation», сгенерированные диаграммы GraphViz будут иметь Z-индекс выше, чем меню, и поэтому будут отображаться над ними даже при расширении меню(см. примечание ниже)не может распознать некоторый тип подсказки по неизвестным причинам.(это исправлено в alpha8, см. примечание ниже)нет поддержки html в описании тегов — теги HTML остаются видимыми, поэтому расширенное форматирование невозможно из того, что я заметил.(см. примечание ниже)
Заметьте, 24 августа: большинство из этих проблем было исправлено в последней протестированной мной версии — альфа 10. Однако отсутствие функции поиска все еще мешает мне.
Докблоки и теги
Мы будем использовать пару классов, которые я написал для целей этого урока, распределенных по паре папок в двух простых пространствах имен. Эти классы не очень пригодятся в реальном мире, но они хорошо послужат нам для этой статьи. Поскольку классы довольно большие со всеми комментариями и интервалами, продиктованными стандартом PSR-2, я загрузил полный код в GitHub. В репо доступно несколько филиалов; первая ветвь «базовый код» не содержит ничего, кроме реальных классов, вторая ветвь «закомментированный код» содержит полностью закомментированный код, а третья ветвь «сгенерированная документация» содержит каталог docs
в котором вы можете найти автоматически сгенерированную документацию ,
Наблюдение за каждым классом заняло бы слишком много времени и места, поэтому вместо этого давайте сосредоточимся только на одном прямо сейчас. Мы посмотрим по частям на класс User
и я объясню docblocks для каждого фрагмента:
<?php /** * This block contains a short description of the classes * present in the rest of this file. * * This paragraph contains the long description of the same * things. * * This entire block will be completely ignored by ApiGen and * is here only to maintain compatibility with PhpDocumentor. * Requiring the presence of this near useless block in every * php file is one of PhpDocumentors downsides. * * @package Some package that only PhpDocumentor sees. */ namespace MyLibrary; use MyLibraryAbstractsSuperType; use MyLibraryInterfacesUserMapper; use MyLibraryExceptionsUser as UserException; class User extends SuperType {
Что должно быть обычной практикой для всех к настоящему времени, мы сначала определяем пространство имен в начале файла класса (игнорируйте весь докблок перед пространством имен, которое существует только для совместимости с PhpDocumentor). Затем мы добавим несколько операторов use
, чтобы установить псевдонимы для классов, используемых классом.
Далее мы видим блок комментария, непосредственно предшествующий объявлению класса. Это описание класса, и оно говорит пользователю / разработчику о том, что класс делает в краткой и краткой манере TL; DR. Описание основного класса обычно состоит из двух частей — краткое описание и длинное описание. Краткое описание — это первый абзац, а длинное описание — это все, от краткого описания до первого маркера докблока (даже несколько абзацев, примеры в строке, все, что думает автор).
Далее следует несколько маркеров, каждый со своим назначением.
@category
указывает категорию, к которой принадлежит класс. Категории являются родителями пакетов (см. Ниже) и образуют большие надмножества классов и утилит. Категории, как правило, такие же охватывающие, как пространства имен, и поэтому наша @category
фактически является названием нашего пространства имен.
@package
определяет меньший, более точный набор классов и утилит. Обычно это подкаталог в главном пространстве имен или, в случае нашего класса User, пакет «Main», что означает, что он находится в корне нашей библиотеки. Есть также маркер @subpackage
который может пойти еще глубже. Обычно в этом нет необходимости (из-за того, что пространства имен хорошо обрабатывают все древовидные структуры), но примером может быть «@category MyLibrary, @package User @subpackage Exceptions», что означает, что класс находится в категории MyLibrary и является пользователем исключение внутри пакета пользователя.
@category
и @package
произвольны, и многие разработчики используют их по своему усмотрению. Специального стандарта не существует, потому что код, в котором должным образом написано пространство, заменяет необходимость в них — пространства имен имеют приоритет над этими маркерами. Некоторым разработчикам даже нравится помечать свои классы как «@category controller», «@category view» и «@category model» в библиотеках MVC. Когда пространства имен не используются, парсеры, такие как ApiGen, будут искать категории и пакеты, чтобы упорядочить вашу документацию, но они предпочитают игнорировать их в пользу пространств имен.
@license
определяет лицензию, которая применяется к коду, и обычно является ссылкой на онлайн-ресурс. Другим полезным маркером может быть маркер @copyright
, который сообщает пользователям, защищены ли авторские права на код. Маркер авторского права обычно содержит годовой диапазон и юридическое лицо, которое защищает код, будь то физическое или юридическое лицо.
@example
— это путь к файлу, содержащему пример использования класса, в котором находится этот маркер. В нашем случае мы указываем, что пример использования класса User
можно найти на один каталог вверх, в файле index.php
. Маркер @example
может также предоставить другой @example
пример. Класс может иметь столько примеров тегов, сколько ему нужно.
@version
является тегом версии и должен изменяться при каждом обновлении.
@since
отмечает дату создания для текущего класса.
@author
указывает разработчика, который создал класс. Это может быть просто имя или адрес электронной почты в формате «Имя». Докблок может содержать несколько авторов, и все они будут перечислены в документации.
Продолжая далее, давайте посмотрим на свойства класса прямо под объявлением класса:
/** * The user's username. Defaults to contact email. * @var string */ protected $sUsername; /** * An array of the user's emails. The first element * is the main contact email. * @var array|null */ protected $aEmails = null; /** * A boolean flag on whether or not the user is logged in * @var bool */ protected $bLoggedIn = false; /** * The mapper is responsible for all data persistence and for * fetching existing records from the database when a username * is provided. * @var UserMapper */ protected $oMapper = null;
Докблоки свойств должны содержать только краткое описание и маркер @var
который указывает на тип значения, которое будет содержать свойство. Если существует вероятность того, что в указанном свойстве содержится несколько типов, можно использовать разделитель каналов, что означает «или» (например, массив | ноль).
Наконец, давайте посмотрим на документацию метода, в данном случае, setUsername()
:
public function setUsername($sUsername) { if (!$this->checkString($sUsername, 5)) { throw new InvalidArgumentException( "The username needs to be a valid non-empty string of 5 characters or more." ); } $this->populate($this->oMapper->findByUnique($sUsername)); $this->sUsername = $sUsername; return $this; }
Докблоки метода всегда начинаются с описания метода, которое должно быть как можно более подробным, чтобы избежать любых проблем, когда его используют другие разработчики.
Список принятых параметров следует за описанием, используя один или несколько маркеров @param
. Каждый маркер должен иметь ожидаемый тип (string, bool, int и т. Д. Или сочетание нескольких типов, разделенных символом канала — array | int | string), фактическое имя параметра в том виде, в каком оно появляется в объявлении метода, и его описание. ,
@return
описывает возвращаемое значение метода. Если метод не возвращает значение, маркер должен сказать «@return void», в противном случае должен быть объявлен определенный тип (например, «@return int» или в нашем случае «@return User», так как метод возвращает экземпляр Сам объект был выполнен). Описание данных является необязательным, но желательно, когда возвращаемые значения могут быть сложными (например, ассоциативные массивы).
Маркер @throws
позволяет разработчику узнать, какие исключения следует ожидать в случае ошибок. Может быть несколько маркеров @throws
, и они могут (но обычно не имеют) описания. Вместо этого ситуация, в которой выдается исключение, обычно описывается в описании метода.
Если метод / класс еще не завершен и некоторые функции еще не добавлены, можно использовать маркер @todo
. Он не только распознается ApiGen и превращается в список задач при создании документации, но также отображается в списке задач во многих современных IDE, что позволяет легко отслеживать незаконченную работу. Докблоки могут иметь столько маркеров задач, сколько они хотят — их даже можно добавить в строку (в середине метода), и они все равно будут распознаваться ApiGen и добавляться в список задач.
Использование @since
и @author
на уровне метода не очень распространено, поскольку обычно достаточно поместить автора и дату в докблок уровня класса, но знание того, какой разработчик добавил таинственный метод в класс, который изначально был вашим, неоценимо в целом команды, в которых несколько разработчиков иногда работают в одном классе. Это совершенно необязательно и требует немного больше времени и нажатия клавиш, но я обнаружил, что преимущества намного перевешивают усилия в больших проектах.
Тег @edit
не является официально поддерживаемым тегом. Это не имеет никакого значения или значения в официальной документации docblock и не ожидается ни одним из известных мне генераторов документации. Я ввел его в действие просто потому, что он необходим для отслеживания изменений кода с помощью средств, отличных от контроля версий. В тандеме с Git или SVN тег @edit
может легко дать вам знать, кто редактировал какой файл, когда и почему — и хештег в конце будет тем же хештэгом, который используется в сообщении коммита редактирования в реальной системе контроля версий. , так что это может быть легко найдено при необходимости. Надлежащий контроль версий и командная работа выходят за рамки этой статьи, но вы бы неплохо применили маркер @edit при работе с чужим кодом — ясность, которую он обеспечивает, когда вы оглядываетесь на свои правки спустя месяцы, может спасти вас бесчисленное множество часы разочарования.
Имея такую документацию, мы гарантируем, что каждый разработчик, открывающий наши файлы в будущем, точно знает, что делает каждый класс, и имеет хорошее автозаполнение независимо от того, какую IDE они используют. Теперь давайте превратим нашу документацию во что-то еще красивее!
Установка и использование ApiGen
Установить ApiGen так же просто, как говорит их сайт. Чтобы установить ApiGen, выполните следующие команды (вам может понадобиться «sudo»):
$ pear config-set auto_discover 1 $ pear install pear.apigen.org/apigen
Вот и все, ApiGen теперь установлен. Если это не работает, попробуйте выполнить некоторые альтернативные инструкции, подробно изложенные на их веб-сайте.
Теперь пришло время запустить ApiGen с некоторыми полезными флагами (все, кроме источника и назначения не является обязательным):
$ apigen --source. Документы назначения / apigen --todo да --title "Моя библиотека документов" --php нет - Скачать да
Флаг --destination
указывает ApiGen поместить документацию в каталог docs/apigen
. Флаг --todo
генерирует список задач из любых @todo
маркеров @todo
. --title
устанавливает заголовок проекта документации, флаг --php
указывает ApiGen игнорировать основные файлы PHP (например, определенные исключения, если они используются), а флаг --download
указывает ему создавать загружаемый ZIP-архив нашего исходного кода как Что ж.
Посмотрите на сгенерированную документацию, открыв index.html
в папке документации или посетив соответствующий URL виртуального хоста в вашем браузере. ApiGen сгенерировал впечатляющий набор HTML-файлов, которые при совместном использовании образуют красивый статический веб-сайт со всей структурой вашего проекта. Вы можете перемещаться по пространствам имен, подпапкам, даже использовать функцию поиска с быстрым автоматическим заполнением в верхнем правом углу и загружать весь сжатый исходный код. Каждое свойство, метод и класс, которые мы определили в проекте, теперь отображаются на экране в структурированной табличной и / или древовидной форме — даже комментарии «todo» (нажмите «todo» в верхней части экрана)!
Все, что вам нужно сделать, чтобы открыть эту документацию для широкой публики, это загрузить ее на свой сервер и указать на нее домен или поддомен — все, что вы увидите в файлах HTML, будет также видно посетителям.
У ApiGen есть множество других полезных флагов (реализация Google Analytics, пользовательский корневой URL-адрес, пользовательская директива конфигурации, стили и т. Д.), Но они выходят за рамки этой статьи и могут быть более подробно рассмотрены в следующей статье.
В заключение
Независимо от того, являетесь ли вы одним разработчиком, работающим над небольшими проектами, или частью большой команды, работающей над совместными усилиями, комментарии важны для вашего рабочего процесса. Если все сделано правильно и с учетом определенных стандартов для всего проекта или для всей команды, это поможет вам и вашим коллегам избежать долгих часов работы при повторном рассмотрении старого кода и позволит пользователям вашего кода получить более плавный опыт его использования. и торчать. Плохая документация является одной из основных причин, по которой новые пользователи сложных библиотек отказываются от них — поэтому, чтобы не отвлекать своих пользователей и коллег, примите эти лучшие практики сегодня.
Изображение через Fotolia