phpDocumentor 1.1 Converters

Joshua Eichorn <jeichorn@phpdoc.org>
Gregory Beaver <cellog@sourceforge.com>

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

Table of Contents

Introduction
Basics
Converter Logic
Converter Data Structures
Converter Methods
parserClass methods you'll find useful
Converter Example

Introduction

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 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.

phpDocumentor Converter basics

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. A Converter must 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." Any other files you wish to use for your converter should reside in the subdirectory (PDFConverter helper files will be in subdirectory PDFConverter."

In other words, if your phpDocumentor source code is located in /usr/local/phpdoc, the PDFConverter must be in /usr/local/phpdoc/PDFConverter/PDFConverter.inc, and all helper files included by PDFConverter.inc must be in /usr/local/phpdoc/PDFConverter.

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
  • class parserPage (defined in parserData.inc)
  • class pageLink (defined in LinkerClasses.inc)
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
  • class parserGlobal (defined in parserData.inc)
  • class globalLink (defined in LinkerClasses.inc)
parserGlobal stores a DocBlock (described below), the name of the defined element, its value, and its file location
Define Statement
  • class parserDefine (defined in parserData.inc)
  • class defineLink (defined in LinkerClasses.inc)
parserDefine stores a DocBlock (described below), the name of the defined element, its value, and its file location
Include Statement
  • class parserInclude (defined in parserData.inc)
parserInclude stores a DocBlock (described below), the include type (include/require/include_once/require_once), its value, and its file location
Function
  • class parserFunction (defined in parserData.inc)
  • class functionLink (defined in LinkerClasses.inc)
parserInclude stores a DocBlock (described below), the function name, its parameters, and its file location
Class
  • class parserClass (defined in parserData.inc)
  • class classLink (defined in LinkerClasses.inc)
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
  • class parserMethod (defined in parserData.inc)
  • class methodLink (defined in LinkerClasses.inc)
parserMethod stores all things that parserFunction does plus its class, and whether it is a constructor
Class Variable
  • class parserVar (defined in parserData.inc)
  • class varLink (defined in LinkerClasses.inc)
parserVar stores a DocBlock (described below), the variable name, and its class
DocBlock
  • class parserDocBlock (defined in parserData.inc)
parserDocBlock stores a short and long description (class parserDesc), plus an array of tags (class parserTag and descendants)

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.

Converter Logic

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.

Converter::walk()

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 in the order found in files, and are not sorted. In version 1.0, A Converter is responsible for sorting output by standards desired. This may change in future versions. for each element traversed, walk() does a number of steps:

  1. sets up $this->package/$this->subpackage to that of the current procedural page
  2. calls $this->Convert() for the page data (parserPage class)
  3. sets $this->class to the name of the class being walk()ed through or false if not in a class
  4. calls $this->endClass() if a class has been finished parsing (abstract method in Converter)
  5. calls $this->Convert() on the current element (the current element can be any one of parserDefine, parserInclude, parserClass, parserFunction, parserMethod, parserVar classes)
  6. on converting all page elements, calls $this->endPage() and begins from step 1
  7. after converting all pages, walk() converts all package pages by calling $this->Convert() with each parserPackagePage element

Converter::Convert($element)

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.

Methods of conversion

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.

function-oriented approach to conversion

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 HTMLConverter::generateElementIndex() and HTMLConverter::generatePkgElementIndex(). This approach should be used in the constructor (for an example, see HTMLConverter::HTMLConverter()), or in the Output() method

object-oriented approach to conversion

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. This approach should be used in the Convert() function.

Converter Data Structures

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, 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 arrays

$methods an array of all parserMethods organized by package name and class name
$vars an array of all parserVars organized by package name and class name
$class_parents_by_name an array of inheritance organized by package
$class_children an array of all child classes by name, organized by package and parent class name
$class_packages an array of package,subpackage organized by class name, helps resolve packaging conflicts

Class objects

$classes a Classes class, which stores all information about every class (can be used instead of using the arrays above, for object-oriented approach)

Linking arrays

$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:
if ($this->class)
{// perform class operations
....
}

Converter Methods You Should Override

walk()ing Methods

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)

parserClass methods you'll find useful

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

Converter Example

The best example of a Converter is included with phpDocumentor as the main conversion engine, HTMLConverter, found in Converter.inc. Future versions of phpDocumentor will include more Converters for output formats such as XML and PDF perhaps.