DocBlock standard
This standard defines the requirements and conventions for adding inline code documentation, known as DocBlock s.
Some parts of the code might not comply with this standard, but we are working to improve this.
Following these standards is optional for third-party developers, but doing so helps to create consistent, clean, and easy to read inline documentation.
Use RFC 2119 to interpret the "MUST," "MUST NOT," "REQUIRED," "SHALL," "SHALL NOT," "SHOULD," "SHOULD NOT," "RECOMMENDED," "MAY," and "OPTIONAL keywords."
Scope of the standard
The goal of this standard is to unify usage of code DocBlocks for all files, not specific to a particular language.
The following is assumed by default:
- Formatting according to the phpDocumentor standard
- Requirements apply for all files regardless of programming language, but a DocBlock standard for the particular language may override it.
General principles
The documentation should follow two simple principles:
- Be as short as possible.
- Include all necessary information without duplication.
Short documentation
The documentation should be as short as possible, while including all necessary details.
Below are ways of improving code to help simplify documentation:
- Make code self-explanatory.
-
Put all possible information in the names of classes, methods, and variables. (e.g. use
$timeInSec
instead of$time
) - Break down a method into smaller methods with descriptive names. For example:
Copied to your clipboardpublic function getPrice(){$price = 0;$price += $this->getBasePrice();$price -= $this->getDiscount();return $price;}private function getBasePrice(){// calculate base price}private function getDiscount(){if (it is discount time) {return 10;}return 0;}
Include all necessary details
-
Identify the details a developer needs to work with your code.
-
Ignore the implementation details (i.e. private methods/properties and method bodies) and focus on what the public interface signature provides. If possible, improve the interface to provide more information.
-
Add any remaining information that a developer may need to the DocBlock.
Files
Each source code file must have a DocBlock header with a short description of the file. After the short description, there can be a long description.
Both short and long descriptions (for file headers and herein) must be separated from other elements using one empty line (implied empty line in terms of DocBlock syntax, where any line within DocBlock starts from
*
.
If the description or short description happens to be the first one after the DocBlock opening tag (
/**
) or last one before the closing tag (
*/
), it should not be separated with an empty line.
DocBlock Header in a PHP-file:
Copied to your clipboard/*** Short description...** Long description* Broken down into several lines** License notice...*/
DocBlock Header in an XML-file:
Copied to your clipboard/*** Autoloader with class map capability** ...*/class Autoload{
While declaring classes or functions, if there must be another file with source code included, the inclusion construct must not be before file header and it must not separate the element DocBlock from the element. There are two solutions possible:
- Have the file header DocBlock separately, then inclusion construct, then a DocBlock for the element with duplicated short description.
- Include it after declaring the element (it is possible in PHP and will not cause issues before execution).
DocBlock with Included Script File:
Copied to your clipboarduse Magento\Logger;use Magento\Math\Random;use Magento\Stdlib\DateTime as StdlibDateTime;/*** @var Logger*/private $logger;/*** Description of method here.** @param Random $mathRandom* @param StdlibDateTime $dateTime* @param int $number*/private function doSomething(Random $mathRandom, StdlibDateTime $dateTime, $number){}
Class attributes
Class attributes must have a type declaration using
@var
tag.
Example of Class Attribute:
Copied to your clipboard/*** Merge the config XML files** @param array $configFiles* @return void* @throws \Magento\Exception if a non-existing or invalid XML file passed*/protected function merge($configFiles){$domConfig = new \Magento\Config\Dom($this->_getInitialXml(), $this->_getIdAttributes());foreach ($configFiles as $file) {if (!file_exists($file)) {throw new \Magento\Exception("File does not exist: {$file}");}$domConfig->merge(file_get_contents($file));if (!$domConfig->validate($this->getSchemaFile(), $errors)) {$message = "Invalid XML file: {$file}\n";/** @var libXMLError $error */foreach ($errors as $error) {$message .= "{$error->message} Line: {$error->line}\n";}throw new \Magento\Exception($message);}}$this->_dom = $domConfig->getDom();}
Divergence in @throws tag
In general, use the
@throws
tag when the code uses
throw
:
Example of Throwing Exception Explicitly:
Copied to your clipboard/*** Set an arbitrary value to specified element** @param string $elementId* @param string $attribute* @param int|string|float|bool|object|null $value* @return self* @throws \InvalidArgumentException*/public function setAttribute($elementId, $attribute, $value){$this->_assertElementExists($elementId);switch ($attribute) {case self::PARENT: // break is intentionally omittedcase self::CHILDREN:case self::GROUPS:throw new \InvalidArgumentException("Attribute '{$attribute}' is reserved and cannot be set.");break;default:$this->_elements[$elementId][$attribute] = $value;break;}return $this;}
In this case, if an exception is thrown in a sub-routine, then
@throws
must not be used in the parent method.
However, if the only purpose of the referred sub-routine is to throw a specific exception – then
@throws
must be used in the parent method.
For example:
Throwing Exception Implicitly:
Copied to your clipboard/*** Perform login process** @param string $username* @param string $password* @return void* @throws \Magento\Framework\Exception\AuthenticationException*/public function login($username, $password){if (empty($username) || empty($password)) {self::throwException(__('The account sign-in was incorrect or your account is disabled temporarily. '. 'Please wait and try again later.'));}try {$this->_initCredentialStorage();$this->getCredentialStorage()->login($username, $password);if ($this->getCredentialStorage()->getId()) {$this->getAuthStorage()->setUser($this->getCredentialStorage());$this->getAuthStorage()->processLogin();$this->_eventManager->dispatch('backend_auth_user_login_success',['user' => $this->getCredentialStorage()]);}if (!$this->getAuthStorage()->getUser()) {self::throwException(__('The account sign-in was incorrect or your account is disabled temporarily. '. 'Please wait and try again later.'));}} catch (PluginAuthenticationException $e) {$this->_eventManager->dispatch('backend_auth_user_login_failed',['user_name' => $username, 'exception' => $e]);throw $e;} catch (\Magento\Framework\Exception\LocalizedException $e) {$this->_eventManager->dispatch('backend_auth_user_login_failed',['user_name' => $username, 'exception' => $e]);self::throwException(__($e->getMessage()? : 'The account sign-in was incorrect or your account is disabled temporarily. '. 'Please wait and try again later.'));}}
@return tag
In general, method return type signatures should be preferred over
@return
type annotations.
If that is not possible due to ambiguous return types or backward compatibility constraints, the
@return
type annotation must be used.
If there is no explicit return statement in a method or function or a return statement without a value, a
void
return type must be declared in the method signature. For example:
Copied to your clipboardfunction setName(string $name): void{$this->name = $name;}
If the method returns itself, the method signature return type must be
self
. Here is an example:
Copied to your clipboardfunction withField(string $fieldName): self{$this->fields[] = $fieldName;return $this;}
If for backward compatibility reasons, no return type can be added to the method signature, a
@return $this
annotation must be used.
Constants
Constants may have a short description. If the short description adds no additional information beyond what the constant name already supplies, the short description must be omitted.
For example, a global constant:
Copied to your clipboard/*** Directory separator shorthand, intended to make code more readable.*/define('DS', DIRECTORY_SEPARATOR);
Or constants in a class:
Copied to your clipboardclass Profiler{/*** Separator literal to assemble timer identifier from timer names*/const NESTING_SEPARATOR = '->';
DocBlock templates
A DocBlock template is a DocBlock that starts from
/**#@+*/
and ends with
/**#@-*/
.
Templates are no longer supported by PHPDocumentor. Therefore, they MUST NOT be used.
It is encouraged to replace existing DocBlock templates with regular DocBlock comments when the file is being modified.
Structure of documentation space
@author
,
@category
,
@package
, and
@subpackage
MUST NOT be used.
Documentation is organized with the use of namespaces.
Other DocBlock tags
@inheritdoc tag
The
@inheritdoc
tag SHOULD NOT be used.
If a child class method requires a long description to explain its purpose, it may use
@inheritdoc
to indicate the new description is intended as an addition to the parent method description.
In general, such method overrides are a
code smell
and should be used as an incentive to make the code more self-documenting if possible.
DocBlock for the Interface:
Copied to your clipboard/*** Get some object** @deprecated Added to not break backward compatibility of the constructor signature* by injecting the new dependency directly.* The method can be removed in a future major release, when constructor signature can be changed* @return SomeObjectInterface*/protected function getSomeObject(){...}/*** Set price** @deprecated Non-scoped price is not supported anymore* @see setScopedPrice()* @return void*/public function setPrice($price){...}/*** Set price for specified scope** @return void*/public function setScopedPrice($price, $scopeType, $scopeId){...}
@var inline tag
For the purpose of automatic type hinting in an IDE, an inline notation of
@var
tag can be used wherever the IDE is unable to resolve variable type.
This tag declares variables that will emerge in following lines of code:
Inline Type Hinting:
Copied to your clipboard/** @var libXMLError $error */foreach ($errors as $error) {
Some IDEs understand a different notation, where the type is specified after variable name. This notation is also valid:
Inline Type Hinting Variation:
Copied to your clipboard/** @var $error libXMLError */foreach ($errors as $error) {
@see tag
Besides the normal way of using
@see
tags as
recommended by phpDocumentor
, it may be used as an addition to
@var
, when the
@var
is already used in this comment.
Specifically, this is possible when a PHP file is composed from multiple file includes. As a result, variables may contain objects of different types depending on context:
Copied to your clipboard/*** @var $this ClassOne* @see ClassTwo* @see FooInterface*/
@method tag
The
@method
allows a class to know which 'magic' methods are callable.
Syntax:
Copied to your clipboard@method [[static] return type] [name]([[type] [parameter]<, ...>]) [<description>]
See
PHP documentation
for more information about the
@method
tag.
Copied to your clipboard@link [URI] [<description>]
Other tags
Any other valid DocBlock tags may be specified, if the author deems it necessary, but only if they bring valuable non-obvious information.
Formatting conventions
Padding tags
If there are two or more tags together in one DocBlock, their values may be padded, so that they could be visually aligned.
Copied to your clipboard/*** ...** @param string $argument* @return bool* @link http://example.com*/
Formatting consistency
In a given DocBlock, the formatting style must be consistent.
For example, padding for visual alignment can be done in two ways:
Correct – align everything:
Copied to your clipboard/*** ...** @param string $parentId* @param string $childId* @param int|null $position* @return int* @see _insertChild() for position explanation*/
Also correct – do not align anything:
Copied to your clipboard/*** ...** @param string $parentId* @param string $childId* @param int|null $position* @return int* @see _insertChild() for position explanation*/public function reorderChild($parentId, $childId, $position)
Incorrect – align only partially: