Home/Section index
 www.icosaedro.it 

 PHPLint Support for phpDocumentor

Last updated: 2009-05-13

PHPLint provides support for the phpDocumentor's DocBlock comments (www.phpdoc.org). PHPLint parses and gathers the informations found inside a DocBlock and merges these informations with those gathered from the PHP source and the PHPLint meta-code.

From a DocBlock, PHPLint acquires not only textual descriptions, but it acquires also the types of variables, function arguments and returned values.

Index

What is a DocBlock
Example
Supported line tags
Types
Literal arrays
The @throws line tag
Supported inline tags
Missing features and differences
References

What is a DocBlock

Constants, variables, functions, classes, class constants, properties and methods can be preceded by a multi-line comment properly formatted. The symbol /** marks the beginning of the DocBlock. Every line of the DocBlock MUST begin with an asterisk "*"; lines missing this asterisk are ignored (PHPLint reports an error). Every line, apart from the asterisk and the possible surrounding spaces, is the content of the DocBlock. The structure of a DocBlock consists of three sections: the short description, the long description and the line tags, in this order.

The short description starts at the first non-empty line and spans up to the first empty line, the end of the DocBlock or the first period not included inside a word. If the short description so determinated results to be more than 3 lines long, only the first line is taken. If the short description was terminated by a period, the period itself is removed. The short description is rendered literally.

All the text between the short description and the first line tag is the long description. The long description can contain a subset of the HTML entities listed below:

<b> <i> <code> <br> <kbd> <p> <pre> <ul> <ol> <li> <samp> <var>

The last two entities are not HTML entities, but special tags defined by phpDocumentor; they are passed unchaged but are ignored by WEB browsers. Currently PHPLint does not allow upper-case letter, nor it allows spaces inside the tags, so take care to write them exactly as indicated here otherwise they would be rendered literally. Moreover, PHPLint checks for proper usage of these entities, and raises an error on unclosed tags, wrong nesting, badly formed punctuated lists, etc.

These tags, and only these, can be used to format the text of the long description. Any other entity or special character including < > & gets rendered literally (i.e. < is converted to &lt; and so on). The text enclosed between <pre> and </pre> is always rendered literally.

The line tags are all the lines with a leading "@" (extra spaces and tabulations between the asterisk and the "@" are ignored). The first line tag found opens the line tags section of the DocBlock.

Example

The following source illustrates the main features of a DocBlock. It declares a package with some copyright, and a function:


<?php

/**
 * PhpDoc test source.
 *
 * This is a <i>package description</i>. This source does nothing
 * useful, it is intended only to illustrate the features of the
 * phpDocumentor and how a DocBlock looks like.
 *
 * @package PhpDocTest
 * @author  Umberto Salsi <phplint@icosaedro.it>
 * @version 1.0
 * @deprecated  Do not use this package, it is completely unuseful!
 */

/*. require_module 'standard'; .*/

/**
 * Last error code found
 * @global int $last_error
 */
$last_error = 0;

/**
 * Search a name inside an array of names. The long description
 * starts with this second sentence.  Both the short
 * description and the long description are optionals.
 *
 * @param string $name    Name of the item we are looking for.
 * @param array[int]string  $arr   List of items.
 *
 *           Note that we have indicated both the type of the
 *           index (int) and the type of the elements
 *           (string): this is a PHPLint extension that
 *           works also for phpDocumentor.
 *
 * @return int   The index of the element found, or -1 if not found.
 */
function searchName($name, $arr)
{
	foreach($arr as $k => $v)
		if( $v === $name )
			return $k;
	return -1;
}

?>

Also the PHP 4 classes can be documented: properties and methods can have a visibility attribute, and methods can have also the static and the final attributes:


<?php
/*. require_module 'pgsql'; .*/

/**
 * Example of class to access to the PostgreSQL DB.
 *
 * @author Umberto Salsi <phplint@icosaedro.it>
 */
class DBAccess {

    /**
     * Name of the current DB
     * @var string
     * @access public
     */
    var $db_name;

    /**
     * Current connection to the DB
     * @var resource
     * @access private
     */
    var $db_conn;

    /**
     * Opens the connection with the given DB
     * @access public
     * @param string $db_name   Name of the DB
     * @return void
     */
    function DBAccess($db_name)
    {
        $this->db_conn = pg_connect("dbname=$db_name");
        if( $this->db_conn === FALSE )
            die("connection to $db_name failed");
        $this->db_name = $db_name;
    }

    /* ... */
}
?>

PHP 5 classes already have their own attributes keywords abstract final static private protected public built-in, and these keywords must be used instead of the DocBlock tags. Also PHP 5 class constants can be documented:

abstract class DBLogger
    extends GenericDB
    implements Logger
{
    /**
     * Timeout for any operation on the DB (s)
     */
    const TIMEOUT = 0.5;

    /**
     * Commenting a method in PHP 5. Note that the @access
     * tag cannot be used since PHP 5 already has its own
     * keyword.
     * @param string $query
     * @return bool
     */
    public abstract function testTimeout($query);

    /* ... */
}

Abstract classes and interfaces can be commented with DocBlocks as you can expect:

/**
 * Documenting an interface class
 */
interface TreeInterface
{
    /**
     * Constants are always public. No type declaration is
     * required, as their value already says all.
     */
    const ROOT_NODE_LEVEL = 0;

    /**
     * Methods are always abstract, public and non-final.
     *
     * @param mixed $key
     * @return void
     */
    function addNode($key);
}

Supported line tags

The syntax of every line tag is described with the aid of these elements:

WORD is any sequence of characters not including spaces, tabulations an new-lines. WORDs are rendered literally.

$VAR is the name of a variable. Note that the dollar sign is required.

TEXT is any text, possibly spanning on several lines up to the next line tag or the end of the DocBlock. A TEXT is rendered literally.

DESCR is an HTML text, and the subset of tags already listed for the long description are allowed. The DESCR can span several lines up to the next line tag or the end of the DocBlock. A DESCR enclosed between square parenthesis [DESCR] is optional.

The following table summarizes all the available line tags, their syntax, and the context where they are legal:


Line tagPHP 4PHP 5
@abstractclass, methodSee note 1.
@access privateconstant, global variable, function, class, property, methodconstant, global variable, function, class, class constant
@access protectedproperty, methodSee note 1.
@access publicproperty, methodSee note 1.
@author TEXT(always)(always)
@copyright DESCR(always)(always)
@deprecated DESCR(always)(always)
@finalclass, methodSee note 1.
@global TYPE $VARglobal variableglobal variable
@license WORD [TEXT](always)(always)
@link WORD [TEXT](always)(always)
@package WORDpackagepackage
@param TYPE [&] $VAR [DESCR]function, methodfunction, method
@return TYPE [DESCR]function, methodfunction, method
@see WORD(always)(always)
@since DESCR(always)(always)
@staticmethodSee note 1.
@throws WORD [DESCR]function, methodSee note 2.
@todo DESCR(always)(always)
@var TYPE [DESCR]propertyproperty
@version TEXT(always)(always)

Note 1. PHP 5 already has the attributes abstract final private protected public static. These keywords must be used instead of the corresponding phpDocumentor line tags.

Note 2. The @throws line tag is explained below in detail.


The supported TYPEs are described in the next paragraph.

PHPLint raises a notice if a line tags is used in the wrong context, for example @var in a function description.

PHPLint raises a warning if a DocBlock omits to declare the type of a variable, function, argument, property or method and this type cannot be guessed from the code.

Types

All the basic PHP types are supported, with the addition of void. The general syntax in EBNF format is:

TYPE = type_name | array;
type_name = "void" | "bool" | "boolean" | "FALSE" | "false"
	| "int" | "float" | "double" | "number" | "string"
	| "resource" | "mixed" | "object" | CLASS_NAME | array;
array = "array" [ index {index} [TYPE] ];
index = "[" ["int"|"string"] "]";

The following table summarize the allowed types:


Type Description
void Functions and methods that do not return a value are declared to retun a value of this dummy type.
bool or boolean A boolean value, either FALSE or TRUE. 0 and 1 are numbers in PHPLint and cannot be used in place of the boolean values.
int or integer An integer number.
float or double A floating point number.
number Either an integer or a floating point number. Probably you should simply use float instead, since int is a subset of this.
string A string of bytes. PHPLint allows also the value NULL.
array Array of undefined key type and undefined elements, equivalent to the PHPLint type array[]. PHPLint allows also the value NULL for a variable of this type.
resource Typically an opened file, or a network socket. PHPLint allows also the value NULL.
object Generic object. PHPLint allows also the value NULL.
CLASS_NAME An object of the specified class. PHPLint allows also the value NULL.
mixed Anything.

An array can be described including the type of the index and the type of the elements. This is an extension of the array type already supported by phpDocumentor. Some examples:


array index can be both integers and strings, elements mixed
array[] index can be both integers and strings, elements mixed
array[int]string array of strings with int index
array[int][int]float matrix of floating-point numbers
array[string]mixed associative array of generic values
array[]SomeClass array of objects of the class SomeClass,
the keys can be both integer numbers and strings

Some functions and methods can return values of different types that can be listed separated by a vertical bar. Many functions of the standard library can return some result or FALSE on error. For example fopen() can return either a resource or the FALSE value. This practice is discuraged by PHPLint, but it is tolerated; in this case PHPLint keeps only the first type, then the remaining types are parsed but ignored. Example:

/**
 * Opens my data file
 *
 * @return resource|FALSE
 */
function my_fopen()
{
    return fopen("data.txt", "r");
}

Note that PHPLint allows to indicate the value FALSE in place of the correct type boolean just to support this common practice. The Tutorial expands this topic with several practical examples. Please, in new software you write (or at least, if it is intended to be validated by PHPLint) try to choose among the alternatives indicated there.

Literal arrays

In PHP, literal arrays can be defined through the array() constructor. PHPLint parses accurately the literal arrays in order to guess their type (both index and elements). The manual of PHPLint explains in detail how these guesses are made. Basically, if no keys are specified, the type of the index default to int. The type of the elements is the type of the expression giving the value of the elements. For example:


Literal array Guessed type
array() array
array( array( ) ) array[int][]
array("AA", "BB") array[int]string
array(0=>"AA", 1=>"BB") array[int]string
array("a"=>"AA", "b"=>"BB") array[string]string
array( new SOME_CLASS() ) array[int]SOME_CLASS
array(array(1.0,0.0), array(0.0,1.0)) array[int][int]float

Note that PHPLint encounters a difficulty when the literal array is empty, because no keys nor elements are available and the resulting type is a generic "array". Such generic type is likely to produce an error if it is assigned to some variable or passed by value to a function. The same hold when the value to be assigned or passed to function is NULL: NULL is a special value that is assignment-compatible with every array, but that cannot provide to PHPLint the informations about the structure of the array.
In these cases the correct type should be indicated through a PHPLint formal type-cast, like in these examples:


<?php
/**
 * List of names, initially empty
 */
$names = /*. (array[int]string) .*/ array();

/**
 * List of names, initially NULL.
 * Here using phpDocumentor line tag.
 * @global array[int]string $names2
 */
$names2 = NULL;

/**
 * List of names, initially NULL.
 * Here using PHPLint formal type-cast.
 */
$names3 = /*. (array[int]string) .*/ NULL;

/**
 * List of names, initially NULL
 *
 * When a @global or @var line tag is used, the type
 * specified must match the type of the expression.
 * In this case, since every array is assignment-compatible
 * with the value NULL, no formal type-cast is required.
 *
 * @global array[int]string $names3
 */
$names3 = NULL;

/**
 * Matrix of coefficients, initially empty
 */
$m = /*. (array[int][int]float) .*/ array();

/**
 * Prints a list of names. This function requires
 * an array of a well defined structure.
 *
 * @param array[int]string $a  the list of names
 * @return void
 */
function print_names($a)
{
    echo count($a), " names in list:\n";
    for($i=0; $i<count($a); $i++)
        echo $a[$i], "\n";
}


print_names( array( "Foo", "Bar" ) );

print_names( /*. (array[int]string) .*/ array() );
/*
    Note the empty list and the formal typecast.
    Without this formal type-cast PHPLint would
    raise an error because array() is not assignment-
    compatible with the formal type expected as
    argument of the function.
*/
?>

The @throws line tag

The @throws line tag is an important extension of PHPLint to the format of the DocBlock, but it is not officially supported by phpDocumentor. phpDocumentor simply reports this line tag verbatim.

The @throws WORD [DESCR] line tag allows to declare an exception the function or the method may throws, where WORD is the name of the exception and DESCR describes the conditions that causes this exception to be thrown:

/**
 * Return the size of the file. On 32-bit systems, this function
 * returns the correct value also for files whose size is up to 4 GB.
 * @param string $filename  Path of the file.
 * @return float  Size of the file (bytes). Being a float, this value
 *                may be greater that the maximum allowed for int.
 * @throws ErrorException  If an error occurs accessing the file.
 */
function BigFileSize($filename)
{
    $size = @filesize($filename);
    if( $size === FALSE )
        throw new ErrorException($php_errormsg);
    if( $size >= 0 )
        return (float) $size;
    else
        return (float) $size + 2.0 * (1.0 + PHP_INT_MAX);
}


interface MyCollection {

    /**
     * Return the element of the given index in the list.
     *
     * @param int $index  Index of the element.
     * @return mixed      The element.
     *
     * @throws OutOfBoundException  If the $index is out of bound.
     *
     * @throws ErrorException       Implementing methods may also throw this,
     *                              depending on the specific code that will
     *                              implement this method.
     */
    function getElement($index);

    ...
}

Usually there is no need to list all the exceptions the method may throw, since PHPLint automatically collects uncought exceptions while parsing the source. As a consequence, the generated document may list more exceptions than those the programmer has explicitly entered in the DocBlock.

The programmer may still add one or more @throws line tag either to add a descriptive text, or also to add an exception that is not currently thrown by the method, but it is planned to be thown later in some overriding or implementing method. In fact, as explained in more details in the PHPLint manual, the list of thrown exceptions is part of the method signature that implementing and overriding methods must comply with. Basically, implementing and overriding methods can only throw the same exceptions the original method throws, or even more specialized exceptions derived from these; it is important to note that implementing and overriding methods cannot throw new, unrelated exceptions.

In the document generated by PHPLint Documentator, thrown exceptions are always listed in the order from more specialized ones to more general ones (that is, parent classes) so to suggest to the programmer the proper order of the catch() statements.

Supported inline tags

The sequence of characters {@ has a special meaning as it is the beginning of an inline tag. The general syntax of an inline tag is as follows:

{@TAG}

Some inline tags may have one or more arguments separated by one or more spaces, tabulator characters or line feed; the general structure of an inline tag requiring arguments is a follows:

{@TAG ARG1 ARG2 ... ARGn}

Inline tags are allowed in the short description, in the long description, and in the descriptive text of line tags that have a descriptive text. Inline tags are not allowed, that is are passed verbatim, in any other location.

The inline tags PHPLint supports are listed below:

{@}
This tag allows to insert the sequence of characters {@ that would be otherwise forbidden because them are reserved to start an inline tag.
{@*}
This tag allows to insert the sequence of characters */ that would be otherwise forbidden in a multi-line comment. It is mostly usefult when a long chunk of code has to be inserted into the text.
{@link ITEM}
{@link ITEM text to be displayed}
{@link URL}
{@link URL text to be displayed}
This tag allows to insert an hypertextual link to some documented item (constant, variable, function, etc.) or to some generic resource available in Internet through an URL. ITEMs can be specified using their name, for example:

{@link M_PI}
inserts a reference to the constant M_PI.

{@link $varName}
inserts a reference to the global variable $varName. Note that the $ symbol is mandatory. Variables that are local to a function or method and formal arguments of function and method cannot be referenced.

{@link funcName()}
inserts a reference to the function funcName(). Note that the perenttheses are mandatory as them allows to distinguish between constants and functions. You may also add specific arguments inside the parentheses, but still spaces are not allowed. For example you may write {@link tan(M_PI)}.

{@link SomeClass}
inserts a reference to the class or interface SomeClass.

{@link SomeClass::SOME_CONST}
inserts a reference to the class constant SomeClass::SOME_CONST.

{@link SomeClass::$aProperty}
inserts a reference to the property SomeClass::$aProperty.

{@link SomeClass::aMethod()}
inserts a reference to the method SomeClass::aMethod(). Between parentheses, you may enter some specific actual argument just like already explained for functions.

In DocBlocks related to a class, the class name itself can be omitted, so bringing to these shorter references:

{@link ::SOME_CONST}
inserts a reference to the class constant SOME_CONST defined inside the same class to which the DocBlock belongs.

{@link ::$aProperty}
inserts a reference to the property $aProperty defined inside the same class to which the DocBlock belongs.

{@link ::aMethod()}
inserts a reference to the method aMethod() defined inside the same class to which the DocBlock belongs.

The ITEMs that can be refereced are only those that are available in the current package, including imported standard modules (see require_module) and imported packages (see require_once). Instead, ITEMs that are not accessible from the current package cannot be referenced directly but, if really needed, a full URL or a relative path can be provided instead.

Private items cannot be referenced.

The {@link} inline tag also allows to insert links either to local file or to remote resources. To avoid URLs and file paths be confused with PHP documented items, URLs must always indicate the protocol used and file paths must always be indicated as relative to the directory of the current document file or as absolute path. For example:

{@link ftp://sources.company.com/myproject/package-1.0.zip}
{@link http://www.company.com/}
{@link mailto:bugs@company.com}
{@link ./anotherPackage.htm}
{@link ../otherLib/otherPackage.htm}
{@link /home/Me/projects/myProject/index.htm}
{@link c:/php-lib/index.htm}

Unsupported inline tags {@example} {@internal} {@inheritdoc} {@source} {@tutorial} are reported verbatim. Invalid inline tags are reported as errors.

Nested inline tags are not allowed.

Missing features and differences

References

www.phpdoc.org - Official WEB site of the phpDocumentor project.


Umberto Salsi

Contact
Site map
Home/Section index