DocumentationDocumentation is inherently important in writing quality code. Although well-written code is largely self-documenting, a programmer must still read the code in order to understand its function. In my company, code produced for clients is not considered complete until its entire external application programming interface (API) and any internal idiosyncrasies are fully documented. Documentation can be broken down into two major categories:
The following sections describe these two types of documentation. Inline CommentsFor inline code comments, PHP supports three syntaxes:
In practice, I avoid using Shell/Perl-style comments entirely. I use C-style comments for large comment blocks and C++-style comments for single-line comments. Comments should always be used to clarify code. This is a classic example of a worthless comment: // increment i i++; This comment simply reiterates what the operator does (which should be obvious to anyone reading the code) without lending any useful insight into why it is being performed. Vacuous comments only clutter the code. In the following example, the comment adds value: // Use the bitwise "AND" operator to see if the first bit in $i is set // to determine if $i is odd/even if($i & 1) { return true; } It explains that we are checking to see whether the first bit is set because if it is, the number is odd. API DocumentationDocumenting an API for external users is different from documenting code inline. In API documentation, the goal is to ensure that developers don't have to look at the code at all to understand how it is to be used. API documentation is essential for PHP libraries that are shipped as part of a product and is extremely useful for documenting libraries that are internal to an engineering team as well. These are the basic goals of API documentation:
In addition, it is often useful to provide the following to end users:
Finally, an API documentation system should provide the following features to a developer who is writing the code that is being documented:
You could opt to build your own system for managing API documentation, or you could use an existing package. A central theme throughout this book is learning to make good decisions regarding when it's a good idea to reinvent the wheel. In the case of inline documentation, the phpDocumentor project has done an excellent job of creating a tool that satisfies all our requirements, so there is little reason to look elsewhere. phpDocumentor is heavily inspired by JavaDoc, the automatic documentation system for Java. Using phpDocumentorphpDocumentor works by parsing special comments in code. The comment blocks all take this form: /** * Short Description * * Long Description * @tags */ Short Description is a short (one-line) summary of the item described by the block. Long Description is an arbitrarily verbose text block. Long Description allows for HTML in the comments for specific formatting. tags is a list of phpDocumentor tags. The following are some important phpDocumentor tags:
You start the documentation by creating a header block for the file: /** * This is an example page summary block * * This is a longer description where we can * list information in more detail. * @package Primes * @author George Schlossnagle */ This block should explain what the file is being used for, and it should set @package for the file. Unless @package is overridden in an individual class or function, it will be inherited by any other phpDocumentor blocks in the file. Next, you write some documentation for a function. phpDocumentor tries its best to be smart, but it needs some help. A function's or class's documentation comment must immediately precede its declaration; otherwise, it will be applied to the intervening code instead. Note that the following example specifies @param for the one input parameter for the function, as well as @return to detail what the function returns: /** * Determines whether a number is prime (stupidly) * * Determines whether a number is prime or not in * about the slowest way possible. * <code> * for($i=0; $i<100; $i++) { * if(is_prime($i)) { * print "$i is prime\n"; * } * } * </code> * @param integer * @return boolean true if prime, false elsewise */ function is_prime($num) { for($i=2; $i<= (int)sqrt($num); $i++) { if($num % $i == 0) { return false; } } return true; } ?> This seems like a lot of work. Let's see what it has bought us. You can run phpDocumentor at this point, as follows: phpdoc -f Primes.php -o HTML:frames:phpedit -t /Users/george/docs Figure 1.3 shows the result of running this command. Figure 1.3. phpdoc output for primes.php.For a slightly more complicated example, look at this basic Employee class: <?php /** * A simple class describing employees * * @package Employee * @author George Schlossnagle */ /** * An example of documenting a class */ class Employee { /** * @var string */ var $name; /** * The employees annual salary * @var number */ var $salary; /** * @var number */ var $employee_id; /** * The class constructor * @param number */ function Employee($employee_id = false) { if($employee_id) { $this->employee_id = $employee_id; $this->_fetchInfo(); } } /** * Fetches info for employee * * @access private */ function _fetchInfo() { $query = "SELECT name, salary FROM employees WHERE employee_id = $this->employee_id"; $result = mysql_query($query); list($this->name, $this->department_id) = mysql_fetch_row($result); } /** * Returns the monthly salary for the employee * @returns number Monthly salary in dollars */ function monthlySalary() { return $this->salary/12; } } ?> Note that _fetchInfo is @access private, which means that it will not be rendered by phpdoc. Figure 1.4 demonstrates that with just a bit of effort, it's easy to generate extremely professional documentation. Figure 1.4. The phpdoc rendering for Employee. |