Primary phpDocumentor Documentation
Note: if this howto looks bad, get a browser that supports css
phpDocumentor HOWTO written by Gregory Beaver and Joshua Eichorn
Copyright © 2002, Gregory Beaver, Joshua Eichorn
Introduction
Differences from Version 1.0
Basics
Converter Logic
Converter Data Structures
Converter Methods
parserClass methods you'll find useful
Converter Example
This howto is intended to be a guide to developers writing new Converters for phpDocumentor. In addition to this howto, please look at the generated documentation for pre-existing converters, and the source code, and you should be rolling very quickly.
phpDocumentor is the most advanced automatic documentation system written for PHP, in PHP. The newest feature since version 1.0 is called Converters, and is similar in scope to JavaDoc's doclet feature. What is a Converter? To understand this, one must first understand the problem that Converters solve. Documentation is not always best viewed as a web page. Sometimes a user may want to print it out, or view it in XML with an interface program that can search or perform other advanced functions. Printing html does not work very well, and may look very different on different user's screens. To solve this problem, we need an interface between the parser and the template engine, hence the Converter.
Warning: geek speak below. Skip if your eyes gloss over at technical details.
On an even more basic level, the linking performed by phpDocumentor requires that the program pass over the data at least twice to set up relationships and create the @see and {@link} hyperlinks that make it such an effective tool. In earlier versions of phpDocumentor, the parser passed over the data twice, with significant redundancy and slow parsing times. In addition, the linking pass had to be first, and the order of parsing was important. In other words, if file A contains class B extends foo, and file B contains class foo, if file A is parsed before file B, no inheritance occurs between the classes (you can try this with 0.4.2a and earlier, it breaks the parser). The Converter works with temporary data structures (all defined in ParserData.inc, ParserElements.inc, and ParserDocBlock.inc if you want a peek), and allows the linking pass to occur in-memory after parsing, with a significant speedup (almost twice as fast as earlier versions).
If you want to write your own output template for phpDocumentor, a Converter gives you all of the tools you need to do it quickly and relatively easily.
The subdirectory hierarchy has changed dramatically thanks to the clever thinking of Thomas Krozl ({@link mailto:daevon@users.sourceforge.net}. Converters are now grouped by output format, and contain templates within their own directory hierarchy. The default HTML Converter, therefore, is in Converters/HTML/default/. In addition, the converter filename must be outputformatconverternameConverter.inc, and the classname must be the same. So the default HTML converter is located in Converters/HTML/default/HTMLdefaultConverter.inc, and the class is named HTMLdefaultConverter. Output format will always be in upper case.
Arguments to the constructor have dramatically decreased, be sure to look at the source for Converter::Converter() and adjust your arguments for any pre-existing converters. You won't need to know about major differences.
There are many, many more helper functions in both descendants of parserElement and in Converter. All elements have a method getLink() which when passed a Converter will return text representing a link to the element's documentation. Be aware that any state information must be encoded in the Converter, such as the HTMLdefaultConverter::$local variable which determines whether links are from a package/subpackage directory or from the documentation root.
All class trees and indexes are sorted by Converter in alphabetical order. In addition, new indexes of specific elements by package (like the left.html element list of the default HTML converter) are generated by Converter. The elements passed to the Convert() method are in alphabetical order. Procedural page elements are passed first, followed by all class elements.
Converter handles any package output and parse private, your code does not need to be aware of any command-line arguments whatsoever.
Converter::walk() now calls several functions that it expects to be overridden in child classes. These functions are: formatPkgIndex(), formatIndex(), formatLeftIndex(), and ConvertErrorLog(). None of these methods are passed any arguments, and you may use them as you please. The formatPkgIndex() method expects you to iterate through the $pkg_elements array and generate an element index for each package as in version 1.0. The formatIndex() method expects you to iterate through the $elements array and generate an element index of all elements documented, as in version 1.0. The new formatLeftIndex() method expects you to iterate through any of the $class_elements, $function_elements, $define_elements, $global_elements, and $page_elements arrays to create a left.html-style index. the new ConvertErrorLog() method should use the global $phpDocumentor_errors ErrorTracker class methods returnWarnings() and returnErrors() to retrieve all parsing errors and warnings and generate a report.
New helper functions include getSortedClassTreeFromClass(), setTemplateDir(), setTargetDir(), writeFile(), and copyFile(). The first, getSortedClassTreeFromClass(), is used to create the sorted class trees from root classes. The returned structure is two-dimensional array that can be iterated over non-recursively (an example is in HTMLdefaultConverter::getRootTree().) The non-recursive algorithm is much faster, but a bit more complicated for the programmer. The other helper functions are self-explanatory and very useful for output.
New helper functions in descendants of parserElement include parserPage::getClasses(), parserElement::getConflicts() (used for classes, defines, globals and functions), parserMethod::getOverridingMethods(), parserMethod::getOverrides()
parserPage::getClasses() returns an array of parserClass classes that represent the classes defined in a procedural page.
parserElement::getConflicts() returns an array of elements that have the same name as the element in other packages. This is useful for documenting errors that would occur should a user include files from the two packages into the same project.
The method helper functions return a list of parserMethods that override this one in child classes, and the parserMethod that this method overrides in a parent class
A Converter is written in PHP. Unlike any other aspect of phpDocumentor, Converters require programming to work. If you only wish to make a simple change to the output generated by phpDocumentor, you may be better off posting a feature request at the SourceForge project webpage http://www.sf.net/projects/phpdocu, or tweaking the code (let us know about your tweak, it may make it into the next version!)
A Converter extends the Converter class, defined in file Converter.inc. In version 1.0, Converters had to reside in a subdirectory with the same name as the class. In other words, for Converter class PDFConverter, phpDocumentor tries to find the file "PDFConverter/PDFConverter.inc." In version 1.1, this is very different!
Converters all reside in the Converters subdirectory, under subdirectories organized by output format and converter name. The default HTML Converter, for example, is in Converters/HTML/default/HTMLdefaultConverter.inc, and the class is named HTMLdefaultConverter.
In other words, if your phpDocumentor source code is located in /usr/local/phpdoc, the default PDF Converter must be in /usr/local/phpdoc/PDF/Converter/PDFdefaultConverter.inc, and all template files used by PDFdefaultConverter.inc must be in /usr/local/phpdoc/PDF/Converter/default/templates.
A Converter must define several methods, and work with abstract data structures that represent the parsed data. Here is a short list of the elements that are parseable and how they are represented by phpDocumentor to a Converter's eyes:
Procedural Page |
|
parserPage stores a page's filename, its alias for PHPDoc linking, package information, and its path. pageLink, like all links, stores information that allows quick linking to an element independent of output format |
NEW in 1.1 Global Variable |
|
parserGlobal stores a DocBlock (described below), the name of the defined element, its value, and its file location |
Define Statement |
|
parserDefine stores a DocBlock (described below), the name of the defined element, its value, and its file location |
Include Statement |
|
parserInclude stores a DocBlock (described below), the include type (include/require/include_once/require_once), its value, and its file location |
Function |
|
parserInclude stores a DocBlock (described below), the function name, its parameters, and its file location |
Class |
|
parserClass stores a DocBlock (described below), the class name, its parent (if an extends clause is present), and its file location. Note that all methods and vars are stored in arrays distinct from the parserClass element |
Class Method |
|
parserMethod stores all things that parserFunction does plus its class, and whether it is a constructor |
Class Variable |
|
parserVar stores a DocBlock (described below), the variable name, and its class |
DocBlock |
|
parserDocBlock stores a short and long description (class parserDesc), plus an array of tags (class parserTag and descendants) |
Package-level Docs |
|
parserPackagePage stores the contents of package-level documentation. |
Whew! To make a long story short, a Converter walks through the parsed data, converting each element into a format suitable for a template engine to do its work. A Converter may itself be a template engine, there are no limits on the possibilities. The best part is that more than one converter may be specified on the command line, and they will run in sequential order.
A Converter is called from phpDocumentor_IntermediateParser automatically, and is passed several arguments used to set up the data structures that will be needed for Conversion to output. Immediately following this, the phpDocumentor_IntermediateParser::Convert() method is called, which then calls a converter's walk() and Output() methods.
The walk() method should NOT be overridden in most cases
The walk() method traverses an array of parsed elements that was generated by the Parser. Elements are sorted in alphabetical order. In version 1.0, A Converter was responsible for sorting output by standards desired, but version 1.1 passes sorted indexes as described above. Individual elements are not sorted. This may change in future versions. for each element traversed, walk() does a number of steps:
This function must be overridden by a Converter for it to do anything.
$element can be any documentable element (parserPage, parserClass, parserInclude, parserDefine, parserFunction, parserMethod, parserVar, parserPackagePage). this function is responsible for all conversion of the element to a template-enabled output format.
There are two ways of approaching conversion of data, and both will be used by any converter. The first is a traditional function-oriented approach, and the second is object-oriented.
In the function-oriented approach, your Converter will operate on the arrays passed to Converter from phpDocumentor_IntermediateParser in its constructor. These arrays are described below in Converter Data Structures. All indexing should work best in this fashion. Example of the function-oriented approach are in HTMLdefaultConverter::generateElementIndex() and HTMLdefaultConverter::generatePkgElementIndex() and HTMLdefaultConverter::formatLeftIndex(). This approach should be used in formatPkgIndex(), formatLeftIndex() and formatIndex()
In the object-oriented approach, your Converter will operate on the classes representing the elements to process their information. The best example of this approach is the parserClass object. The parserClass object includes several utility methods, including getParent(), getMethods(), getMethodNames(), getInheritedMethods(), getVars(), getVarNames(), getInheritedVars(), getChildClassList(), and getParentClassTree() that make writing a converter much simpler. New in version 1.1, the parserElement class has utility method getConflicts(), which can be called from parserClass, parserFunction, parserDefine, or parserGlobal elements, the parserMethod class includes utility methods getOverridingMethods() and getOverrides(), and the parserPage class includes utility method getClasses(). This approach should be used in the Convert() function.
The rest of this document is lists that may be helpful during development. For detailed information
All parser and linker classes: parserPage, parserClass, parserDocBlock, parserStringWithInlineTags, parserTag, parserInlineTag, parserClass, parserFunction, parserInclude, parserGlobal, parserMethod, parserVar, parserDefine, classLink, defineLink, pageLink, functionLink, methodLink, varLink are documented in depth in the generated documentation included with this release, and are not documented here. You need to know how these objects work before proceeding. |
|
Indexing arrays |
|
$elements | an array of all elements |
$pkg_elements | an array of all elements organized by package name |
$class_elements | an array of all classes organized by package name |
$page_elements | an array of all procedural pages organized by package name |
$define_elements | an array of all defines organized by package name |
$global_elements | an array of all global variables organized by package name |
$function_elements | an array of all functions organized by package name |
Class objects |
|
$classes | a Classes class, which stores all information about every class |
Procedural Page objects *NEW in 1.1* |
|
$proceduralpages | a ProceduralPages class, which stores all information about every procedural page and its contents (includes, defines, functions, global variables) |
Linking arrays |
|
These arrays should not be used directly, instead use the get*Link() methods (getClassLink, getPageLink, etc.) | |
$links | array organized by package, subpackage, element type, and element name of abstractLink class descendants used for linking (@see and {@link}) |
$linkswithfile | identical to $links, except organization is by the file the element is found in |
Data used in walk() |
|
$package | a string containing the current package name |
$subpackage | a string containing the current subpackage name |
$class | a string containing the current class name, or a boolean false if no class is being parsed. This can be used like:
|
walk()ing Methods |
|
formatIndex() *NEW 1.1* | called to convert the complete element index into output |
formatPkgIndex() *NEW 1.1* | called to convert the element indexes by package into output |
formatLeftIndex() *NEW 1.1* | called to convert the element indexes by element type and package into output |
ConvertErrorLog() *NEW 1.1* | called to convert the $phpDocumentor_errors log of parsing warnings/errors into an output log |
Convert() | called to convert every element (see above) |
endClass() | called at the conclusion of converting a class and all of its vars and methods |
endPage() | called at the conclusion of converting a page and all of its contained elements |
Output Methods |
|
Output() | Perform the actual file output or call the template engine's output function |
Linking Methods | |
for all of the get****Link methods, you should call Converter::get****Link() and operate on the returned abstractLink class descendant to return a string that is a link (in html, it's an <a> tag) | |
getVarLink($expr,$class,$package,$file=false) | $expr is a class variable name with leading $ ($varname) |
getMethodLink($expr,$class,$package,$file=false) | $expr is a method method name with no () (methodname not methodname()) |
getPageLink($expr,$package) | $expr is a procedural file name with no path (file.ext) |
getDefineLink($expr,$package,$file=false) | $expr is a defined constant name |
getGlobalLink($expr,$package,$file=false) | $expr is a global variable name |
getFunctionLink($expr,$package,$file=false) | $expr is a function name with no () |
getClassLink($expr,$package,$file=false) | $expr is a class name |
returnLink($link,$text) | this function should return a string that is a link to $link with viewable text $text |
returnSee(&$element, $eltext = false) | this function should return a string that is a link to $element with viewable text $eltext. $element is a descendant of abstractLink (see HTMLConverter::returnSee() for more information) |
getState() *NEW 1.1* | called by the parserStringWithInlineTags::Convert() cache to retrieve state for the next Convert() call |
checkState() *NEW 1.1* | called by the parserStringWithInlineTags::Convert() cache to check whether the cache hit or missed |
All of these methods require that you pass a Converter to them as the first parameter - none of them will work before the Conversion stage of parsing.
parserClass Methods |
|
getParent(&$c) | this method returns false if the class does not extend a parent class, or a parserClass object representing the parent class |
getMethods(&$c) | this method returns false if the class has no methods, or an array of parserMethod objects |
getMethodNames(&$c) | this method returns false if the class has no methods, or an array of method names (no ()) |
hasMethod(&$c,$name) | this method returns true if the class contains a method by the name of $name (no inheritance checks) |
hasVar(&$c,$name) | this method returns true if the class contains a variable by the name of $name (no inheritance checks). The name should include the leading $ |
getVars(&$c) | this method returns false if the class has no vars, or an array of parserVar objects |
getVarNames(&$c) | this method returns false if the class has no vars, or an array of var names. The names will include the leading $ |
getInheritedMethods(&$c,$override = false) | returns an associative array of methods inherited by the class in the format (parentclassname => array of parserMethods). if $override is true, overridden methods will not be returned |
getInheritedVars(&$c,$override = true) | returns an associative array of vars inherited by the class in the format (parentclassname => array of parserVars). if $override is true, overridden vars will not be returned |
getParentClassTree(&$c,$arr = false) | returns an associative array of parserClass objects indexed by parent class name. The root class indexes to false. In other words, if class C extends class B, and class B extends class A, the returned array for class C will be array("A" => false,"B" => parserClass A,"C" => parserClass B) |
getChildClassList(&$c) | returns a simple array of parserClass objects representing every class that extends the class |
parserPage Methods *NEW 1.1* |
|
getClasses(&$c) | this method returns false if no classes are defined on the procedural page, and an array of parserClasses if there are any classes defined on the procedual page. |
parserMethod Methods *NEW 1.1* |
|
getOverridingMethods(&$c) | this method returns false if no methods in child classes override this method, otherwise it returns an array of parserMethods. |
getOverrides(&$c) | this method returns false if this method does not override a method in a parent class, otherwise it returns the parserMethod that is overridden. |
parserElement Methods *NEW 1.1* |
|
getConflicts(&$c) | this method returns false if there are no name conflicts with elements in other packages, otherwise it returns an array of conflicts in the format array(package => parserElement) where parserElement is the same type class as the one calling getConflicts(). This method may be called by parserClass, parserFunction, parserGlobal, and parserDefine. |
The best example of a Converter is included with phpDocumentor as the main conversion engine, HTMLdefaultConverter, found in Converters/HTML/default/HTMLdefaultConverter.inc. Future versions of phpDocumentor will include more Converters for output formats such as XML and this version includes a pre-alpha PDF Converter.