Docblock structure¶
These rules check the docblocks asked for in Drupal's
API documentation and comment standards:
a docblock on every file, class, function and property, its summary and description, and its tags.
They don't check the types in a docblock against the real signature, which is done by
mago analyze, see
Docblock types and the analyzer.
The rules read a docblock the way Coder does. A tag is a line that starts with @. Two kinds of
@ lines stay text. An @ line below another tag, indented like that tag's description, stays part
of the description. An indented @code, @endcode, @link or @endlink stays part of the text
around it. Coder reads both as tags. Only the tags at the column of the first one form the groups
looked at by the blank-line checks.
A declaration without a docblock gets the report of its missing-* rule, and one with a comment in
the wrong style the report of drupal/class-comment, drupal/file-comment,
drupal/function-comment or drupal/variable-comment. The rules that check the tags, their
wording and their layout skip such a declaration, as in Coder. They also skip the tags of a
docblock tagged @file above a function, which counts as no docblock for the function.
Comment-style fixes¶
drupal/class-comment, drupal/file-comment, drupal/function-comment and
drupal/variable-comment report a // run or a /* */ comment right above the declaration, where
a docblock belongs. Their fix turns the comment into a docblock, with an @file tag for a file. A
file comment that already starts with @file keeps it once.
The fix is potentially unsafe. PHP's reflection returns a docblock and not a comment, so
annotation discovery, PHPUnit and the analyzers start to read the text. It skips a trailing comment
of the line above, a comment that a blank line parts from the declaration, a directive, and a line
comment that holds */. It also skips a comment below the attributes when a docblock sits above
them, because PHP reads only the lower of two docblocks.
drupal/class-comment¶
- Level: error
- Fix: safe for the blank line. Potentially unsafe for the comment style.
- Standard: General considerations for API module parsing, General documentation
- Ports:
Drupal.Commenting.ClassComment:Short,SpacingAfter,WrongStyle
To document a function, class, etc., the docblock must appear directly before the item being documented, with no blank line in between (see example above).
All summaries (the first line of a docblock) must be under 80 characters, start with a capital letter, and end with a period (.). They must provide a brief description of what a function does, what a class does, what a file contains, etc.
Reports, on a class, interface, trait or enum:
- a comment in the wrong style where the docblock belongs;
- a summary that only repeats the name. The name is matched in any case, so
bar.aboveclass Baris reported; - a blank line between the docblock and the declaration, which is removed by the fix.
A docblock above or below the attributes counts. A docblock tagged @file is the file's, and
drupal/missing-class-comment reports the class as undocumented.
Example
// Reported.
/**
* Example.
*/
class Example {
}
// Fine.
/**
* Provides an example of a documented class.
*/
class Example {
}
Compared with Coder
- Coder matches the repeated name with case, so it doesn't report
bar.aboveclass Bar. - Coder reports a summary that repeats the name as a warning. The rule reports it at error level.
drupal/constant-comment¶
- Level: error
- Fix: safe. It removes the blank line.
- Standard: General considerations
- Ports: none. Coder doesn't check it.
To document a function, class, etc., the docblock must appear directly before the item being documented, with no blank line in between (see example above).
Reports:
- a blank line between a docblock and the class constant, global
constor enum case below it. A docblock above the attributes of a constant counts.
drupal/function-comment, drupal/class-comment
and drupal/variable-comment report the same for a function, a class
and a property.
Not reported:
- a docblock with an
@file,@defgroup,@addtogroupor@mainpagetag, or with@{or@}, which stands on its own; - a
define()call, which is a function call and not a declaration.
Example
The fix turns the reported code into the fine code.
// Reported.
/**
* The number of items on a page.
*/
const EXAMPLE_PAGE_SIZE = 50;
// Fine.
/**
* The number of items on a page.
*/
const EXAMPLE_PAGE_SIZE = 50;
drupal/deprecated-tag¶
- Level: warning
- Fix: safe for the punctuation after the link. Potentially unsafe for the rewrite of an old wording.
- Standard: @deprecated
- Ports:
Drupal.Commenting.Deprecated:DeprecatedMissingSeeTag,DeprecatedPeriodAfterSeeUrl,DeprecatedVersionFormat,DeprecatedWrongSeeUrlFormat,IncorrectTextLayout,MissingExtraInfo
The
@deprecatedtag is placed in a documentation block to indicate that a function, method, or class has been deprecated and should not be used, but has not yet been removed.@deprecated in %deprecation-version% and is removed from %removal-version%. %extra-info%. @see %cr-link%
Reports:
- a
@deprecatedtag whose text breaks that grammar. A version isdrupal:n.n.n,project:n.x-n.norproject:n.n.n, with an optional release label such as-alpha1, as indrupal/deprecation-message. The text may wrap over several lines; - a
@deprecatedtag with no@seetag after it; - a change-record URL in another form, or with punctuation after it. The URL is the first line of
the
@seetag. Coder 9 acceptshttps://www.drupal.org/node/n,https://www.drupal.org/project/name/issues/nandhttps://git.drupalcode.org/project/name/-/work_items/n.
A safe fix removes the punctuation after the URL.
A potentially unsafe fix rewrites an old core wording on the text's first line, such as
in Drupal 8.5.x and will be removed before Drupal 9.0.0., as phpcbf does. It writes drupal:
versions with three parts and drops the text before in or as of and between the two versions.
Other layouts are reported without a fix.
Example
// Reported.
/**
* Returns the label.
*
* @deprecated in example:1.1.0 and is removed from example:2.0.0. Use
* example_title() instead.
*/
function example_label(): string {
return '';
}
// Fine.
/**
* Returns the label.
*
* @deprecated in example:1.1.0 and is removed from example:2.0.0. Use
* example_title() instead.
*
* @see https://www.drupal.org/node/3123456
*/
function example_label(): string {
return '';
}
Compared with Coder
- Coder reports a missing
@see, punctuation after the URL, a wrong layout and missing extra info as errors. The rule reports every check at warning level.
drupal/doc-comment¶
- Level: error
- Fix: safe for most checks. The closer fix and the two-dot fix are potentially unsafe.
- Standard: General documentation, {@inheritdoc}
- Ports:
Drupal.Commenting.DocComment:ContentAfterOpen,InheritDocWithoutBraces,ShortStartSpace,SpacingAfter,SpacingBeforeShort,SpacingBetween,TagValueIndent,WrongEndDrupal.Commenting.DocCommentAlignment:NoSpaceAfterStar,SpaceAfterStarSlevomatCodingStandard.Commenting.ForbiddenComments.CommentForbidden
Put a space between the comment character (the
*or the//) and the first letter of the sentence.Note the {} around the @inheritdoc tag.
The rule checks the whitespace and the edges of every docblock outside a function body. A docblock inside a function body gets the star check and the two-dot check only.
Reports, each with a fix:
- text on the line of the opening
/**; - blank lines at the start or the end;
- more than one blank line between the summary and the description;
- not exactly one space before the summary or after a tag;
- the space after the star of a docblock line: no space, and more than one space or a tab before
@param,@return,@throws,@ingroupor@var. This check covers a docblock that comes before a declaration keyword or right after the<?phptag; @inheritdocwithout braces in a docblock with no summary, as its first tag or the tag after a leading@file. The fix writes{@inheritdoc}.
The rest, each with a potentially unsafe fix, because it drops characters of the comment:
- a closer other than
*/, such as**/. The fix writes*/; - a line that ends in two dots. The fix removes one.
Not reported:
- in a docblock whose first tag, or the tag after a leading
@file, is@defgroup,@addtogroup,@}or@coversDefaultClass, everything but the checks on its first and last lines, the star check and the two-dot check; - an empty docblock. Mago's
no-empty-commentreports it, and its safe fix deletes the docblock.
mago format sets the star column and adds a missing star, see Comment whitespace and the
formatter.
Example
The fix turns the reported code into the fine code.
// Reported: the text on the opening line, and the blank line at the end.
/** Returns the label.
*
*/
function example_label(): string {
return '';
}
// Fine.
/**
* Returns the label.
*/
function example_label(): string {
return '';
}
Compared with Coder
- Text on the line of the opening
/**is reported once. Coder also reports it asSpacingBeforeShort. - The space after the star is checked in the docblocks picked by Coder's
DocCommentAlignment: the ones whose next token isclass,interface,function,public,private,protected,static,abstractorvar, and the one right after the<?phptag. Afinal class, an enum, a trait, a constant or a docblock followed by an attribute isn't checked. - The space before the summary is checked in every docblock outside a function body, as
ShortStartSpace, and that includes two spaces or a tab. - A fix for a closer doesn't exist in phpcbf. Its two-dot fix removes both dots. Later passes put a full stop back on a summary and on the last line of a long description, so a middle line of a long description loses its full stop, and a docblock with nothing but the dots ends up empty. The rule turns the two dots and the spaces before them into one full stop, and leaves the docblock.
- Coder reports an empty docblock as
DocComment.Empty, at error level. - The pattern in core's phpcs config that forbids
@inheritDocanywhere in a docblock line isn't ported.
drupal/doc-see-tag¶
- Level: error
- Fix: safe. It removes a colon after
@see, and the punctuation after a one-word reference. - Standard: @see
- Ports:
Drupal.Commenting.FunctionComment:EmptySees,SeeAdditionalText,SeePunctuationDrupal.Commenting.VariableComment.EmptySees
Each
@seereference is on its own line, with no additional text beyond the item being referenced.
Reports:
- a
@seetag with no reference on its line, in the docblock of a function, a method or a property; - a
@seereference with other text after it, or with punctuation at its end, in any docblock outside a function body. The standard asks this of every@seetag, and Coder reads only those of functions and methods. Punctuation at the end of other text is part of that text, so the tag gets one issue; - a colon right after
@see, as in@see: https://www.drupal.org/i/3536307, in the same docblocks. The fix turns the colon and the spaces after it into one space, or removes them when nothing follows. The reference after the colon is checked as above.
The reference is read from the tag's own line. The lines below it are a description, which may end
in a period. The punctuation fix is left out for a @see after @deprecated, whose change-record
URL is fixed by drupal/deprecated-tag.
Not reported:
- the references in a docblock whose first tag, or the tag after a leading
@file, is@defgroup,@addtogroup,@}or@coversDefaultClass, unless it is a function's or a method's; - a
@seetag with no reference in a property docblock with{@inheritdoc}.
Compared with Coder
- phpcs reads
@see:as a tag of its own, so Coder 8 and Coder 9 don't check it at all. The rule reports the colon and checks the reference after it.
drupal/doc-sentence¶
- Level: error
- Fix: safe. It uppercases a lower-case first letter of the summary and the long description,
and adds a full stop to the summary and to a
@paramdescription. - Standard: General documentation, @throws
- Ports:
Drupal.Commenting.DocComment:LongNotCapital,ShortFullStop,ShortNotCapital,ShortSingleLineDrupal.Commenting.FunctionComment:ParamCommentFullStop,ParamCommentNotCapital,ThrowsNoFullStop,ThrowsNotCapital
All summaries (the first line of a docblock) must be under 80 characters, start with a capital letter, and end with a period (.).
If you include an explanation, like other documentation use complete sentences that stand alone, without assuming that "Throws [exception name]" is part of the sentence automatically, since Throws will be a heading when it's displayed on api.drupal.org.
The rule checks the summary and the long description of every docblock outside a function body,
and the @param and @throws descriptions of a function or method. The summary and the long
description of a file docblock are the lines after @file, checked like any other docblock's.
Reports, in the summary and the long description:
- a summary that doesn't start with an upper-case letter. A summary that starts with a digit,
#,_or other punctuation counts, and one that starts with a multi-byte character doesn't. The fix uppercases a lower-case letter; - a summary with no punctuation at the end. The standard asks for a full stop, but as in Coder,
!,?and)pass too. The fix adds a full stop to a one-line summary that ends with a letter or a digit; - a summary that spans more than one line;
- a long description that starts with a lower-case letter. The fix uppercases it.
In the tags:
- a
@paramdescription whose first line doesn't have an upper-case letter anywhere. That line is the first one below the tag, or the text on the tag's line when the tag doesn't have text below it. Solower Case.passes and_lower.is reported; - a
@paramdescription with no full stop, unless it ends in an@codeexample. The fix adds the full stop unless the description ends in a URL, a tag, or:,,or;; - a
@throwsdescription that starts with a lower-case ASCII letter, or doesn't have a full stop.
drupal/long-description-punctuation checks
the end of the long description.
Not reported:
{@inheritdoc}in place of a summary, and a summary that is the file's name;- a
@paramwith no type, which doesn't get a capital letter or full stop check; - a docblock whose first tag, or the tag after a leading
@file, is@defgroup,@addtogroup,@}or@coversDefaultClass.
Example
The fix turns the reported code into the fine code.
// Reported.
/**
* returns the label
*/
function example_label(): string {
return '';
}
// Fine.
/**
* Returns the label.
*/
function example_label(): string {
return '';
}
Compared with Coder
- Coder reads a line that starts with an
@word as a tag, at any indent. When no tag at the@param's column follows, Coder ends the description at the last such line indented deeper than the description, and checks the full stop on the line above it. It does the same when the description's last line holds only an@word. In core'sbatch_set()docblock, theprogress_messageitem has such a line,@total.')".. This rule reads every line indented under the tag as part of the description. - Coder reads a
@throwsdescription from the lines below the tag only. This rule starts at the text on the tag's line, when there is some. So@throws \Exception Some textwithand more below.on the next line is reported by Coder asThrowsNotCapital, and isn't reported here. A description on the tag's line gets onlyThrowsCommentfrom Coder, whichdrupal/doc-tag-layoutports. This rule also checks its capital letter and full stop.
drupal/doc-tag-descriptions¶
- Level: error
- Fix: none
- Standard: Functions
- Ports:
Drupal.Commenting.FunctionComment:ExtraParamComment,MissingParamComment,MissingReturnComment,ParamMissingDefinition,ParamNameNoMatch
A
@paramtag must have a description, unless all of the following are true:A
@returntag must have a description, unless all of the following are true:
Reports, in the docblock of a function or method:
- a
@paramwith no description. On a tag with no type, a single word after the variable is the type and not a description, so the description is the lines below; - a
@returnwith a type and no description on the lines below it. As in Coder, text on the tag's own line is part of the type, so@return string The label.and@return array<int, string>without text below are reported too, with the description asked for on the line below; - a
@paramwith a type that repeats an earlier tag, or that comes after the tag of a later parameter. As in Coder, the tags must follow the order of the parameters, and a parameter can be left out; - a
@paramwith a&in front of the name of a parameter that isn't taken by reference, as in@param int &$a; - a method with
@paramtags for some parameters and none for a real parameter. So in a method, a repeated tag that takes the place of another parameter's tag gets two reports. In a function it gets one, as in Coder.
Not reported:
- no description on
@return void,@return staticor@return $this; - a
@returnwith a variable name after its type, which is reported bydrupal/doc-tag-layout; - the order of a
@paramwith no type, which is reported bydrupal/doc-tag-types; - a
@paramthat doesn't name a parameter, or a parameter in another case.mago analyzereports it asinvalid-param-tag.
The standard lets a @param or @return description be left out when the type says it all, such as
a single class type that can't be null, and asks to leave out @return when the function doesn't
return anything. Coder, core and this rule still want the description. Coder 9 and this rule accept
@return void without one. Coder 8, which is run by Drupal 11.4 and earlier, reports it.
Example
// Reported.
/**
* Builds the label.
*
* @param int $id
* The ID.
*
* @return string
*/
function example_label(int $id): string {
return (string) $id;
}
// Fine.
/**
* Builds the label.
*
* @param int $id
* The ID.
*
* @return string
* The label.
*/
function example_label(int $id): string {
return (string) $id;
}
Compared with Coder
- Coder reports a repeated tag that sits past the number of parameters, such as the third
@param int $aof a function with one parameter, asExtraParamComment. This rule reports it as a repeated tag. - Coder reports
@param int ...$afor a parameter that isn't variadic as a name that doesn't match. This rule leaves it tomago analyze, which reports it asinvalid-param-tag.
drupal/doc-tag-groups¶
- Level: error
- Fix: safe for the blank lines.
- Standard: Order of documentation sections
- Ports:
Drupal.Commenting.DocComment:ParamGroup,ParamNotFirst,SpacingAfterTagGroup,SpacingBeforeTags,TagGroupSpacing,TagsNotGrouped
Separate different-type sections by a blank line (for instance, all the
@paramdocumentation goes together, with a blank line before the first parameter and a blank line after the last parameter before the@returnsection starts).
The rule checks the docblocks outside a function body. As in Coder, it checks the @param group
and the blank lines only in a docblock that starts with a summary, or with @file and one.
Reports:
@paramtags that aren't in one group, or that aren't in the first group;- tags of one kind that aren't grouped. Only
@param,@returnand@throwscount here; - not exactly one blank line before the tags. The fix adds or removes the blank lines;
- no blank line between the
@param,@returnand@throwssections and the tags next to them, and more than one after a section. The fix adds or removes the blank lines.
Not reported:
- no blank line before the tags when the first one is
@code,@linkor@endlink, or aphpcs:line comes right before it; - a
@paramgroup that isn't first in a docblock that starts with@code,@todo,@link,@endlinkor@codingStandardsIgnoreStart; - a docblock whose first tag, or the tag after a leading
@file, is@defgroup,@addtogroup,@}or@coversDefaultClass.
Example
The fix turns the reported code into the fine code.
// Reported: the blank lines around the @param section.
/**
* Returns the label.
* @param string $id
* The ID.
* @return string
* The label.
*/
function example_label(string $id): string {
return $id;
}
// Fine.
/**
* Returns the label.
*
* @param string $id
* The ID.
*
* @return string
* The label.
*/
function example_label(string $id): string {
return $id;
}
Compared with Coder
- The
@paramgroups follow Coder: a@paramright below an@code,@todoor@linktag, with no blank line, is reported, and so is a@paraminside an@codeexample that sits at the column of the first tag. The@paramgroups of a file docblock are checked too.
drupal/doc-tag-layout¶
- Level: error
- Fix: safe. A type with spaces doesn't get one.
- Standard: @param, @return, @throws
- Ports:
Drupal.Commenting.FunctionComment:ParamCommentIndentation,ParamCommentNewLine,ParamNameDot,ParamTypeSpaces,ReturnCommentIndentation,ReturnTypeSpaces,ReturnVarName,SpacingAfterParamType,ThrowsComment,ThrowsCommentIndentation
The
@paramtag is followed by an optional data type indicator, then the variable name of the parameter, and then a newline.The documentation is indented two spaces (see example).
The name of an exception class should appear on the same line as the
@throwstag. Put explanations in starting on the next line, but only if they tell you something useful that is not conveyed by the name of the class.
Reports, in the docblock of a function or method, with a fix where the list says so:
@param:- a description on the tag's line, which is moved below by the fix, and one not indented three spaces from the star, which is indented by the fix;
- a period after the variable name, and not exactly one space between the type and the variable, both fixed;
- a type with a space;
@return: a description not indented three spaces from the star, which is indented by the fix. A variable name after the type, which is removed by the fix when a description follows below. A type with a space;@throws: a description on the tag's line, which is moved by the fix to the line below, three spaces from the star. A description indented less than three spaces, which is indented by the fix. A deeper indent isn't reported, as in Coder.
A @return variable name is read from the tag's own line.
Example
The fix turns the reported code into the fine code.
// Reported: the @param description on the tag's line.
/**
* Builds the label.
*
* @param int $id The ID.
*
* @return string
* The label.
*/
function example_label(int $id): string {
return (string) $id;
}
// Fine.
/**
* Builds the label.
*
* @param int $id
* The ID.
*
* @return string
* The label.
*/
function example_label(int $id): string {
return (string) $id;
}
Compared with Coder
- A
@paramtype is the text before the variable, and a@returntype is the text on the tag's line, as in Coder. Both skip a type with a bracket. A@returntype with a space is reported only when a description follows below, and only when the docblock has one@return. A non-breaking space isn't whitespace to Coder or to this rule. - A
@returnvariable name is a type and one variable on the line, as in Coder, socallable(int $a): intisn't one. - For
@throwstext on the tag's line without text below, Coder counts the words on the line. It reports a type such as\Foo2Baror\A|\Bthat doesn't have any text, and stops at the first@throwswith no text below it. This rule reports only text after the type, and checks every@throws. A fix for that text or for the@throwsindent doesn't exist in Coder. The fix here isn't offered for a tag that shares its line with the closing*/. - A
@paramline with only trailing whitespace after the variable isn't reported. Coder reads that whitespace as a description on the tag's line. - A run of dots after the variable name, as in
$names..., is reported with no fix, because it can be a variadic written out. phpcbf removes the dots. A name followed by a comma, as in$a,..., isn't reported. Coder reports it.
drupal/doc-tag-types¶
- Level: error
- Fix: safe. It moves a type written after the variable in front of it.
- Standard: @param, @return, @throws
- Ports:
Drupal.Commenting.FunctionComment:DuplicateReturn,InvalidThrows,MissingParamName,MissingParamType,MissingReturnType
The
@paramtag is followed by an optional data type indicator, then the variable name of the parameter, and then a newline.Data types are required to be included as of Drupal 8.x.
The name of an exception class should appear on the same line as the
@throwstag.
Reports, in the docblock of a function or method:
- a
@paramwith no variable name, and one with no type, or with nothing after the tag. A&or...in front of the variable belongs to the variable, so@param &$adoesn't have a type. On a tag with no type, a single word after the variable is the type. The fix moves that word in front of the variable when it is made of type characters, as in@param $a int; - a
@returnwith no type on its line; - a
@throwswith no exception class on its line. A class on the line below is read as a description, as in Coder; - more than one
@return.
Compared with Coder
- phpcbf moves any single word after the variable of a tag with no type, so
@param $a Done.becomes@param Done. $a. The fix here moves only a word made of type characters. It moves the word as written, so@param $a integerbecomes@param integer $a, and a second--fixrun writesint, the name asked for bydrupal/doc-type-name. - A
@return 0has a type here. Coder reports it, because PHP'sempty("0")is true. - A
@paramindented inside an@codeexample isn't a tag here, or for the other rules that read the tags. Coder reads it as one.
A tag with nothing after it is also reported by Mago's valid-docblock rule, as a note, and by
mago analyze, as invalid-docblock.
drupal/doc-type-name¶
- Level: error
- Fix: safe. It writes the expected name and drops the punctuation, when the type starts the tag's line.
- Standard: Data types in documentation
- Ports:
Drupal.Commenting.FunctionComment:IncorrectParamVarName,InvalidReturnDrupal.Commenting.VariableComment.IncorrectVarType(partly)
Spell the following types accordingly
- array (NOT "Array").
- bool (NOT "boolean" or "Boolean"). If only TRUE or only FALSE is a possible value, rather than either one being possible, use true or false instead of bool.
- true (NOT "TRUE", see bool)
- false (NOT "FALSE", see bool)
- int (NOT "integer")
- null (NOT "NULL")
- object (NOT "stdClass")
Reports:
- a
@paramor@returntype name of a function or method, and a@vartype name of a property, spelled another way than the standard and Coder ask, such asintegerforint,BooleanforboolorNULLfornull. Each member of a|union is checked; - one of these types that ends in
.,;or!, such as@var string.or@return int;.
Not reported:
stdClass, which isn't checked by Coder either;- a type that ends in
,, which Coder keeps, or in the...of a variadic parameter; - a
@paramtype with a space in it, and a type inside a generic, such asarray<integer>; - a
@vartag with no type or one that starts with a variable name, which are reported bydrupal/variable-comment, and a property docblock with{@inheritdoc}.
Compared with Coder
- Coder runs the whole
@varline, description included, through its type check, and reports a line with a character outside its type alphabet, such as.,;,!or=. So a description that containse.g.or ends in a full stop is reported, and so is a float literal type such as1.5|2.5. The rule only checks a.,;or!at the end of the type. - Coder reads
@param int. $aas a tag with no variable name, since its type stops at the first.. The rule reports the type and its fix drops the.. - The rule reads the
@vartype apart from the description. It reports@var integer Some description, where Coder takes the whole text as the type and doesn't report it. - In a
@paramor@returntype, Coder drops every character outside its type alphabet, such as a non-breaking space betweenintandstring, reports the type asintstring, and phpcbf writes that. The rule doesn't report it.
drupal/file-comment¶
- Level: error
- Fix: safe for the
@filetag and the blank lines. Potentially unsafe for moving the tag, for deleting the docblock of a namespaced class file, and for the comment style. - Standard: @file
- Ports:
Drupal.Commenting.FileComment:FileTag,NamespaceNoFileDoc,SpacingAfterComment,WrongStyle(partly)SlevomatCodingStandard.TypeHints.DeclareStrictTypes.IncorrectWhitespaceBeforeDeclare
Files that comply with the PSR-4 standard SHOULD NOT have a @file documentation block.
The docblock must be followed by a blank line, and must not contain
@defgroupor@mainpagetags.
Reports, on the comment at the start of a file:
- a docblock with no
@filetag. A tag that isn't exactly@file, such as@FILEor@File, counts as no tag. The fix adds@filebelow the opener when a blank line parts the docblock from the code; - no blank line between the docblock and the code. This covers a file docblock right above
declare. The fix adds it, andmago formatturns more than one into one; - an
@filetag that isn't on the line right below the opener. A potentially unsafe fix moves a tag that stands alone on its line, when the opener is alone on its line too; - a comment in the wrong style. A
@codingStandardsIgnoreFileline stays a directive; - a comment at the start of a file with a
namespacestatement and exactly one class, interface, trait or enum. This check runs on every PHP file that Mago reads. The fix deletes a docblock at the start, with the whitespace after it. The text of the docblock is lost, so the fix is potentially unsafe. A plain comment doesn't get a fix; - no blank line between a
declare(strict_types=1)that is the first statement and the comment right above it, asSlevomatCodingStandard.TypeHints.DeclareStrictTypesasks. Any comment counts here, a directive such as// @mago-expecttoo, and the check runs on a class file too. The fix adds the blank line.
Reports, anywhere in the file, and without a fix:
- a second docblock with an
@filetag. The standard says of the API module that it "will only recognize one file docblock per file (the first one; there shouldn't be more than one)"; - an
@defgroupor@mainpagetag in a docblock with an@filetag. Both tags need a docblock of their own.
Coder doesn't check either.
The comment is the first one after the first open tag, past any directive. A file that doesn't start
with one is reported by drupal/missing-file-comment.
Not reported:
- a class file, which is skipped by the checks above, except the last two. Which files count as
class files is in the entry of
drupal/missing-file-comment; - a docblock at the start of a namespaced file with two or more classes, interfaces, traits or enums;
- no blank line above
declarewhen the comment there already has a report above: a comment that must go, a comment in the wrong style, or a file docblock with no blank line after it.
Example
The fix turns the reported code into the fine code.
// Reported.
/**
* Helpers for the example module.
*/
function example_helper(): void {
}
// Fine.
/**
* @file
* Helpers for the example module.
*/
function example_helper(): void {
}
Compared with Coder
- A directive at the start of the file, such as
// phpcs:disableor// @mago-expect, is skipped, and the comment below it is checked. Coder doesn't find a file comment after aphpcs:directive, so it doesn't report anything in a namespaced class file. - The report of a missing
@filesits on the second line of the docblock, where it is put by Coder, or on the opener when the docblock doesn't have a star line. Coder puts it on the first line of the file in that case. - A blank line between the docblock and a
?>that follows it isn't reported. Coder reports it (TemplateSpacingAfterComment).
drupal/function-comment¶
- Level: error
- Fix: safe for the blank line. Potentially unsafe for the comment style.
- Standard: General considerations for API module parsing
- Ports:
Drupal.Commenting.FunctionComment:SpacingAfter,WrongStyle
In-code comment lines starting with
//and comment blocks starting with/*are not recognized as a docblock.To document a function, class, etc., the docblock must appear directly before the item being documented, with no blank line in between (see example above).
Reports, on a function or method:
- a comment in the wrong style where the docblock belongs. A docblock above or below the attributes counts;
- a blank line between the docblock and the function, which is removed by the fix.
drupal/doc-tag-descriptions,
drupal/doc-tag-layout, drupal/doc-tag-types,
drupal/doc-type-name, drupal/doc-see-tag and
drupal/doc-sentence check the tags of the docblock, and
drupal/missing-function-comment a function with no docblock.
Not reported:
- a blank line below a docblock tagged
@file, which belongs to the file.
drupal/hook-comment¶
- Level: warning
- Fix: potentially unsafe. It replaces a description that repeats the function name.
- Standard: Hook implementation
- Ports:
Drupal.Commenting.HookComment:HookCommentFormat,HookParamDoc,HookRepeat,HookReturnDoc
Documentation uses a short format:
/** * Implements hook_help(). */ function blog_help($section) {Do not document parameters and return value though -- these are documented on the hook definition referenced in the summary line.
Reports:
- a hook implementation that isn't documented as
Implements hook_foo()., such as one that repeats the function name, as inImplements my_mod_help().; - a hook implementation with
@paramor@returndocumentation, which repeats the hook's.
The rule reads functions declared at the top level of a file, and only a docblock that touches the
function keyword.
Not reported:
- a hook function whose summary doesn't start with
Implements, such asShows the help page.; - a function in a block, in
namespace X { }or in another function; - a docblock that has a comment, an attribute or a
?>between it and thefunctionkeyword.
The rule also reads a method with a #[Hook] attribute, which is skipped by Coder, and applies the
same summary, @param and @return checks as for a function. The standard predates OOP hooks and
doesn't mention methods. Core writes the Implements hook_foo(). summary on nearly all of its
#[Hook] methods, and the change records for OOP hooks show it too, so the rule asks for it. A
method's docblock may sit above or below its attributes.
The fix replaces a description that repeats the function name, as in Implements my_mod_help().,
with Implements hook_help().. For a hook with a placeholder it writes the function's own words,
as in hook_node_insert() for hook_ENTITY_TYPE_insert(). It applies in a procedural file, when
the function name starts with the file's machine name and an underscore.
Example
// Reported.
/**
* Implements hook_help().
*
* @param string $route_name
* The route name.
*/
function example_help($route_name) {
}
// Fine.
/**
* Implements hook_help().
*/
function example_help($route_name) {
}
Compared with Coder
- The rule joins the lines of a short description with nothing between them, and a tag on the
line right below joins in too. So
Implements foo()with.on the next line is a repeat, and a@paramright belowImplements foo().isn't. - Trailing whitespace after the full stop doesn't hide a repeat. Coder misses it.
- phpcbf takes the machine name up to the first underscore of the function name, so it writes
hook_mod_helpformy_mod_helpinmy_mod.module, where the rule writeshook_help. - Coder reports a description that repeats the function name as an error. The rule reports it at warning level.
drupal/inline-variable-comment¶
- Level: warning
- Fix: potentially unsafe, because the analyzers start to trust the type.
- Standard: In-line code comments
- Ports:
Drupal.Commenting.InlineVariableComment:VarInline,VarInlineOrder
When documenting variables with the
@vartag note that you should use the special/** */delimiters with a double opening asterisk. Always use the fully qualified namespace of the class or interface, and include the name of the variable at the end.
Reports:
- an inline
@vardeclaration in a//comment, as in// @var \Drupal\node\NodeInterface $node; - a
@vartag that writes the variable name before the type, as in/** @var $node \Drupal\node\NodeInterface */.
Not reported:
- a
//or#comment that holds*/, such as a commented-out docblock; - a comment or docblock when the first code after it, past any other comments, is a declaration
keyword such as
public,const,staticorfunction, orinclude,requireor their_onceforms. A comment in the wrong style there is left to the comment-style check of that declaration's rule. On a property,drupal/variable-commentreports a@vartag that starts with a variable name.
One fix moves a variable name written first after the type, when the tag's own line holds a whole
type. The lines below the tag stay as they are. The other turns a comment that holds only the tag,
alone on its line, into a docblock. It skips a comment with more text than the tag, and a // line
inside a run of // lines.
drupal/missing-class-comment¶
- Level: error
- Fix: none
- Standard: Classes and namespaces
- Ports:
Drupal.Commenting.ClassComment.Missing
All classes and all of their methods (including private methods but excluding constructors) must be documented.
Reports:
- a class, interface, trait or enum with no docblock. A docblock tagged
@filedoesn't count as the class docblock.drupal/file-commentchecks it. A docblock above or below the attributes counts.
drupal/class-comment reports a comment in the wrong style.
Compared with Coder
- phpcbf writes an empty docblock for a class that doesn't have one, which is then reported by
Coder as
DocComment.Empty. The rule doesn't have a fix there.
drupal/missing-file-comment¶
- Level: error
- Fix: none
- Standard: @file
- Ports:
Drupal.Commenting.FileComment.Missing
The @file doc block MUST be present for PHP files, with the following exceptions:
- Files that comply with the PSR-4 standard SHOULD NOT have a @file documentation block.
- The core \Drupal class's Drupal.php file (which does not have a namespace).
Reports:
- a file that doesn't start with a comment. This check reads every file with a PHP open tag. The
comment must follow the first open tag. Text before that tag, such as a
#!/usr/bin/env phpline or a byte order mark, which is reported bydrupal/byte-order-mark, doesn't count. A directive such as// phpcs:ignoreFileis skipped.
drupal/file-comment checks the comment that is there: its style and its
@file tag.
Not reported:
- a class file. Which files count as class files follows Coder: a file that holds a class,
interface, trait or enum and a
namespacestatement, and a file that holds exactly one class, interface, trait or enum, no function or method outside it, and no@filetag in any docblock. A closure or an arrow function doesn't count as a function. A method of an anonymous class outside the class does.
Compared with Coder
- A directive at the start of the file, such as
// phpcs:disableor// @mago-expect, is skipped, and the comment below it counts. Coder doesn't find a file comment after aphpcs:directive, so it reports a missing one in a file that isn't a class file. It takes a@codingStandardsIgnore,@mago-,@phpstan-or@psalm-comment for the file comment. - phpcbf writes an empty stub for a missing docblock. The rule doesn't have a fix there.
drupal/missing-function-comment¶
- Level: error
- Fix: none
- Standard: Classes and namespaces
- Ports:
Drupal.Commenting.FunctionComment.Missing
All classes and all of their methods (including private methods but excluding constructors) must be documented.
Reports:
- a function or method with no docblock. A docblock tagged
@fileabove a function counts as no docblock for the function. A docblock above or below the attributes counts.
drupal/function-comment reports a comment in the wrong style.
Not reported:
- a constructor with nothing above it. A constructor with a docblock is checked by the other rules;
- in Drupal core, a function outside the directories where that check is run by core's
phpcs.xml.dist:core/lib, a module'ssrc/Plugin, theDatabase,Functional,FunctionalJavascript,Kernel,KernelTestsandUnitdirectories, and theHookOrdertest module.
Compared with Coder
- The constructor name is matched in any case, because PHP ignores case in method names. Coder
matches
__constructexactly and reports__CONSTRUCTas missing a docblock. A function named__constructoutside a class isn't a constructor and is reported. Coder exempts it. - phpcbf writes an empty docblock for a function that doesn't have one, which is then reported
by Coder as
DocComment.Empty. The rule doesn't have a fix there.
drupal/missing-property-comment¶
- Level: error
- Fix: none
- Standard: General documentation, @var
- Ports:
Drupal.Commenting.VariableComment.Missing
Every function, constant, class, interface, class member (function, property, constant), and file must be documented, even private class members.
The comment may be omitted if the name of the variable matches the type, or the type with "Interface" appended.
Reports:
- a class property with no docblock. A docblock above or below the attributes counts, and a comment between the attributes and the property is the property's comment.
drupal/variable-comment reports a comment in the wrong style.
The standard lets a property with a native type skip the comment when its name matches the type,
as in protected EntityTypeManagerInterface $entityTypeManager, but Coder, core and this rule
still want it.
drupal/missing-summary¶
- Level: error
- Fix: none
- Standard: General documentation
- Ports:
Drupal.Commenting.DocComment.MissingShort(partly)
All summaries (the first line of a docblock) must be under 80 characters, start with a capital letter, and end with a period (.). They must provide a brief description of what a function does, what a class does, what a file contains, etc.
Reports:
- a docblock outside a function body that has tags and no summary. The rule looks only at the
first tag, or at the tag after a leading
@file. The summary of a file docblock is the text after its@filetag, so a file docblock that holds only@fileis reported.
Not reported:
- no summary when the first tag, or the tag after a leading
@file, is@covers; - a bare
@inheritdocthere, which is reported bydrupal/doc-commentas missing its braces; - a docblock whose first tag, or the tag after a leading
@file, is@defgroup,@addtogroup,@}or@coversDefaultClass; - a docblock whose first tag is
@mainpage, which marks the main page of the API documentation; - in Drupal core, no summary outside the
KernelTests,UnitandFunctionalJavascriptdirectories, where that check is run by core'sphpcs.xml.dist.
Compared with Coder
- A
phpcs:line above the summary is skipped, and the line below it is the summary. Coder reportsMissingShortthere. - Coder reports a docblock that starts with
@mainpage, which is the form given by the standard's tag reference.
drupal/variable-comment¶
- Level: error
- Fix: safe for the repeated name and the blank line. Potentially unsafe for a variable name before the type, because the analyzers start to trust the type, and for the comment style.
- Standard: @var
- Ports:
Drupal.Commenting.VariableComment:DuplicateVar,EmptyVar,InlineVariableName,MissingVar,VarOrder,WrongStyle
The
@vartag is used to document the data type of a class property.Typed class properties may omit the
@vardeclaration. It is recommended to use typed properties whenever possible.
Reports, on a class property:
- a comment in the wrong style where the docblock belongs. A docblock above or below the attributes counts, and a comment between the attributes and the property is the property's comment;
- no
@vartag on a property with no native type, more than one, and one that isn't the first tag; - a
@vartag with no type; - a
@vartag that starts with a variable name, as in@var $count int; - the property name repeated after the
@vartype on the tag's line, also after a type with spaces such asarray<string, int>; - a blank line between the docblock and the property, which isn't checked by Coder. The standard
says that "the docblock must appear directly before the item being documented, with no blank
line in between".
drupal/function-commentanddrupal/class-commentreport the same for a function and a class. The fix removes the line.
A missing @var tag is reported on the */ of the docblock, where Coder reports it, so a
phpcs:ignore on the docblock's last line covers it.
The fix removes a property name repeated after the @var type. In a @var tag that starts with a
variable name, a fix writes the type first when a whole type follows the name. It drops the
property's own name, and moves any other name after the type.
drupal/missing-property-comment reports a property with no
docblock, and drupal/doc-type-name the @var type name.
Not reported:
- a docblock with
{@inheritdoc}.
Example
The fix turns the reported code into the fine code.
// Reported: the repeated property name.
class Example {
/**
* The number of items.
*
* @var int $count
*/
protected $count = 0;
}
// Fine.
class Example {
/**
* The number of items.
*
* @var int
*/
protected $count = 0;
}
Compared with Coder
- Coder reports a
@vartag that starts with a variable name asIncorrectVarType, and phpcbf writescount intfor$count int, which is broken. The rule writes the type first. - Coder reports a name after a type with spaces, as in
@var array<string, int> $name, asIncorrectVarType, and phpcbf drops the$of the name. The rule reports it as a repeated name, and the fix removes it. - The rule skips a docblock with
{@inheritdoc}in any letter case, and reads tag names in any letter case. Coder skips only{@inheritdoc}and{@inheritDoc}, and doesn't take@VARfor@var. - The fix removes a repeated name only when it is the property's own name, in a declaration of one property, followed by a space or the end of the line. It keeps a description after the name. phpcbf also removes another name, and drops the description.
- Coder asks for a
@vartag on a property whose type is made only ofself,parent,null,trueandfalse, such as?selforself|null, static or not. Coder looks for a type name before the property name, and phpcs reads those words as keywords. It accepts every other typed property without the tag, such asint,?int,arrayor?Foo. The standard lets typed properties leave@varout, and this rule follows it.