PHPDoc - Sourcedokumentation in PHP

Beitrag zum ersten deutschsprachigen PHP-Kongress, 05/06.10.2000.

Ausgangssituation

Der Umfang von Webapplikationen hat in den letzten Jahren rasant zugenommen. Waren vor drei Jahren das interaktive Webformular oder ein Terminkalender noch "state of art", so äußern Kunden heute andere Wünsche. Schlagworte wie E-Commerce, Content-Management und B2B fallen täglich und zeigen die gewachsenen Ansprüche.

Aus kleinen Skripten sind echte Applikationen erwachsen, die die Benutzung von wiederverwendbaren Codes, z.B. in Form von Programmbibliotheken, zur Pflicht machen. Gute Bibliotheken sind flexibel, leistungsfähig, leicht erweiterbar und vor allem eines: gut dokumentiert. Letzteres entscheidet wesentlich über die Akzeptanz eines bestehenden Codes und damit auch über den kommerziellen Erfolg einer Software. Wer kennt nicht die Situation, daß nach dem Wegfall eines Programmierers bestehende Lösungen verworfen werden, weil der neue Programmierer glaubt, daß es einfacher sei, das Rad neu zu erfinden, statt den Schlauch zu flicken.

Arten von Dokumentation

Dokumentation kennt unterschiedliche Zielgruppen, Inhalte und Sprachen. Entscheidungsträger suchen den schnellen Überblick zur Leistungsfähigkeit einer Software. Einsteiger benötigen Kochrezepte und illustrative Beispiele, um schnell Erfolgserlebnisse zu erzielen und behutsam an die Materie herangeführt zu werden. Erfahrene Programmierer benötigen in der täglichen Arbeit eine API-Referenz und im Einzelfall auch Informationen über Implementationsdetails. Doch nicht nur dem Anwender hilft die Dokumentation. Während der Erstellung einer Dokumentation wird das vorhandene Material erneut gesichtet, und Schwächen in der API können entdeckt, letzte Unstimmigkeiten beseitigt werden.

So reizvoll der Gedanke an gut dokumentierte Software auch ist, so selten trifft man sie in der Praxis an. Zeitdruck und mangelnde Erfahrung in der Erstellung von Dokumentationen erschweren die Aufgabe. Hilfsmittel fehlen bislang in der PHP-Welt. Während Kochrezepte, Tutorials und Aufsätze zu Implementationsdetails nicht automatisch erstellt werden können, kann ein Tool bei der API-Dokumentation helfen.

Bedeutung der API-Dokumentation

Java stellt sich der Forderung nach einem wiederverwendbaren Code in einem ganz besonderen Maße. Es gilt die Maxime "write once, run everywhere". Platformunabhängige Bibliotheken bilden ein wichtiges Standbein dieser Politik. Die Dokumentation der Bibliotheken trägt entscheidend zum Erreichen des Zieles bei. Entsprechend wurde der Entwicklung eines leicht handhabbaren Dokumentationstools eine besondere Bedeutung zugemessen, "Javadoc" wurde entwickelt. Javadoc steht für einfache Dokumentationskommentare im Quellcode, welche die Basis einer API-Dokumentation bilden. PHPDoc ist eine in PHP geschriebene Adaption von Javadoc, die den Bedürfnissen von PHP gerecht wird. So kann z.B. nicht nur objektorienter Code dokumentiert werden, sondern auch prozedualer.

Was sind "Doc Comments"?

Die Erstellung einer API-Dokumentation sollte für den Programmierer so einfach und bequem wie möglich sein. Es bietet sich an, spezielle Dokumentationskommentare, auch "Doc Comments" genannt, im Quellcode zu plazieren. Ohne Unterbrechung der Programmiertätigkeit kann die Dokumentation geschrieben werden. Doc Comments haben eine einheitliche äußere Form, enthalten Dokumentationstags und stehen vor bestimmten Keywords. Ein PHPDoc-Dokumentationskommentar beginnt mit "/**", gefolgt von einer beliebigen Anzahl von Zeilen, die mit einem "*" beginnen, und endet mit einer Zeile, in der nur "*/" steht.
			
/**
* Erste Zeile: Kurzbeschreibung für Übersichtsseiten
* 
* Beliebige Anzahl von weiteren Zeilen, welche die Aufgabe und Benutzung des 
* dokumentierten Elements beschreiben. Es folgt, zur besseren Lesbarkeit 
* durch eine Leerzeile abgesetzt, eine Liste von "Tags", welche die Eigenschaften 
* beschreiben und Dokumentationstags enthalten. 
*
* Die Reihenfolge Übersichtssatz - Kommentarblock - Tagliste ist vorgeschrieben. 
*
* @param		string	Name der Aktion.
* @return 	string	Nachricht, die mit der Aktion verbunden ist.
* @access		public	
* @see			printMessage(), $MESSAGES
* @author		Ulf Wendel <ulf.wendel@phpdoc.de>
* @version	1.0 18/09/2000 15:57
*/
function getMessage( $action ) {
	return (isset($this->MESSAGES[$action])) ? $this->MESSAGES[$action] : "";
}
		
	
Die innere Struktur des Doc Comment ist ebenfalls vorgeschrieben. Die erste Zeile ist eine Kurzbeschreibung, welche für Übersichtsseiten benutzt wird. Es folgt ein Kommentarblock, welcher die Aufgabe und die Benutzung des dokumentierten Elements beschreibt, und schließlich eine Liste von Dokumentationstags.

Die einzelnen Elemente können und sollten zur besseren Lesbarkeit durch Leerzeilen gegliedert werden. Leerzeilen werden ignoriert.

Welche Elemente können dokumentiert werden?

Ein Kommentarblock wird nur dann als Doc Comment erkannt, wenn er der äußeren Form entspricht und vor einem bestimmten Schlüsselwort steht. Lediglich Modulkommentare weichen von dieser Regel ab. Schlüsselwörter sind:

PHPDoc-Tags

Das Ende eines Dokumentationskommentars bildet eine Liste von Tags, welche die Eigenschaften eines Elements beschreiben. Jedes Tag beginnt mit einem "@", gefolgt von einem in Kleinbuchstaben geschriebenen Namen. Nicht alle Tags sind vor jedem Keyword erlaubt, schließlich macht es keinen Sinn, @param[eter] zur Beschreibung von Funktionsargumenten vor einem "define()" zu notieren.

PHPDoc kennt derzeit folgende Tags:

Betrachtet man die Liste der vordefinierten Tags, so erkennt man vier Gruppen von Tags. Alle Tags mit objektorientiertem Hintergrund beschreiben Eigenschaften, die PHP nicht zur Verfügung stellt. So gibt es keine Unterscheidung zwischen public und private oder gar Exceptions (@throws). Dennoch wurden die Tags aufgenommen, um ein Mittel zu schaffen, das andeutet, wie das dokumentierte Element zu benutzen ist.

Zu den Besonderheiten zählen @exclude, @brother/sister, @magic und @todo. @exclude kann benutzt werden, um Elemente von der Dokumentation auszuschließen. @brother/sister dient der horizontalen Informationsvererbung, @magic ist ein Beispiel für einen frei definierbaren Tag. @todo hilft, einen Überblick über den Status der Arbeiten zu wahren.

@module, @modulegroup und @package dienen der logischen Gruppierung von Codeelementen. Als Package wird eine thematisch zusammengehörige Sammlung von Modulen (Modulgruppen) und Klassen verstanden.

Prozedualer und objektorientierter Code

PHPDoc ist in der Lage, prozedualen und objektorientierten Code zu verarbeiten und bietet die Möglichkeit, objektorientierte Gruppierungen in die prozeduale Programmierung zu übertragen. Das Gegenstück zur Klasse ist ein Modul (@module), eine Basisklasse mit allen abgeleiteten Klassen entspricht der Modulgruppe (@modulegroup).

Objektoriente Programmierung   Prozeduale Programmierung
Klasse - "class" Keyword   Module - kein Keyword
Klassenbaum, Basisklasse und abgeleitete Klassen Modulegruppe

Das logische Konstrukt des Moduls kennt keine Entsprechung im PHP-Sprachumfang. Modulkommentare sind deshalb die einzigen Doc Comments, die nicht vor einem Keyword stehen. Es gelten andere Regeln bei der Erkennung: Ein Kommentar ist ein Modulkommentar, wenn keine Klasse in der Datei enthalten ist, der Kommentar am Anfang des Dokuments steht und die Tags @module sowie @modulegroup enthält.

Informationsvererbung

Innerhalb von objektorientierten Codes findet, wie von Javadoc gewohnt, eine Informationsvererbung statt. Ist ein Element in einer Basisklasse dokumentiert, in einer abgeleiteten Klasse jedoch nicht, so werden die Informationen aus der Basisklasse an die abgeleitete Klasse vererbt. Teilweise dokumentierte Elemente werden um Informationen aus der Basisklasse ergänzt. Dies erlaubt es, nur die Unterschiede zur Basisklasse zu notieren.

Neben der vertikalen Informationsvererbung, die nur bei objektorientiertem Code zur Verfügung steht, können Informationen auch horizontal vererbt werden. Elemente einer Klasse oder eines Moduls, die sich nur geringfügig voneinander unterscheiden, können als Geschwister deklariert werden. Benennt ein Element einen Bruder oder eine Schwester, so erbt es alle Informationen aus der Dokumentation des Bruders bzw. der Schwester, die nicht in der eigenen Dokumentation enthalten sind; printMessage() könnte "@brother getMessage()" benennen und lediglich den ersten Satz des Doc Comment überschreiben, der auf den Indexseiten Verwendung findet.

Reports

PHPDoc ist in der Lage, undokumentierte Elemente zu erkennen und zu analysieren, was es gleichzeitig in die Lage versetzt, im begrenzten Rahmen Angaben aus Doc Comments mit dem Sourcecode zu vergleichen. Unvollständige Parameterangaben werden ebenso erkannt wie fehlerhafte Typangaben für Klassenvariablen. Die Programmierer werden somit aktiv in ihrer Dokumentationstätigkeit unterstützt.

Indizes und Klassenhierarchien

Indizes und Visualisierungen von Klassenhierarchien erleichtern den schnellen Überblick. Klassen, Module und Packages werden genauso in Übersichten zusammengefaßt, wie eine Gesamtliste aller Elemente (Klassen, Klassenvariablen, Module, Funktionen, Konstanten, eingebundene Files) erstellt wird.

Datenexport

Anders als Javadoc stellt PHPDoc keine API zum Zugriff auf die extrahierten Daten zur Verfügung. Stattdessen werden die gewonnenen Daten so früh wie möglich als XML-Dokument auf der Festplatte abgelegt. Die frühe Externalisierung minimiert den Speicherbedarf. XML als weithin anerkanntes, universelles Datenaustauschformat ermöglicht die einfache Konvertierung der Daten in andere Darstellungen und Formate wie HTML, PDF und DocBook. Durch die weite Verbreitung von XML ist es einfach, PHPDoc in größere Systeme einzubinden.

Von Haus aus ist PHPDoc in der Lage, das generierte XML in HTML-Dokumente umzuwandeln. Hierzu bedient es sich der Templateklasse aus der PHPLib. Die Anpassung der HTML-Ausgabe ist entsprechend einfach.

Die Erstellung eigener Renderer ist ebenfalls möglich und wird vom Programmdesign unterstützt.

Programmaufbau

PHPDoc ist objektorientiert programmiert und verfügt über einen modularen Aufbau. Ein kleiner Kern kontrolliert das Zusammenspiel der einzelnen Module: Der Parser durchsucht die übergebenen Dokumente, extrahiert die Doc Comments und wertet sie aus. Er arbeitet auf der Basis von regulären Ausdrücken. Informationsvererbung findet im Analyser statt. Der Indexer baut sukzessiv Übersichtsseiten auf, der Report Generator nimmt Warnmeldungen der Module zum späteren Export entgegen. Mit Hilfe des XML Exporter werden die gewonnenen Daten gespeichert.

Der XML Reader ist die Basis für die Gruppe der Renderer, er liest die generierten XML-Dokumente ein und bietet eine einheitliche API zum Zugriff auf die Daten.

Hilfsfunktionalität stellen der XML Writer, der File Handler und letztlich der ArgV Handler (Kommandozeilenparameter) zur Verfügung.

Programmablauf

PHPDoc wurde mit Blick auf objektorientierte Programmbibliotheken wie PEAR (PHP Extension and Add-on Repository) geschaffen, die eine Vielzahl von Packages enthalten und damit über einen großen Codeumfang verfügen. Viele Bibliotheken verwenden eine gemeinsame Basisklasse in allen Packages. Java leitet die meisten Klassen von java.lang ab, PEAR Packages basieren auf der Klasse PEAR.

Diese Eigenschaften haben Rückwirkungen auf den Programmablauf. Innerhalb von objektorientiertem Code soll Dokumentation vererbt werden, während der Bearbeitung einer abgeleiteten Klasse muß ein Zugriff auf die Daten der übergeordneten Klassen möglich sein. Idealerweise stehen die Daten im Speicher zur Verfügung.

Der große Codeumfang einer Programmbibliothek verbietet jedoch das Einlesen aller Daten vor der Informationsvererbung. Ein Prescan zur Ermittlung der enthaltenen Klassenbäume bietet die Basis für eine erste Optimierung. Nacheinander wird jeder Baum in den Speicher geladen und verarbeitet.

Leider vermindert dieses Vorgehen nur dann den Speicherverbrauch, wenn keine Superklasse verwendet wurde, es also mehr als einen Baum gibt, und die gefundenen Bäume relativ klein sind. Für die geforderte Informationsvererbung ist es jedoch nicht notwendig, den gesamten Baum im Speicher zu halten, da nur innerhalb eines Astes Daten vererbt werden.

Speicherverbrauch ohne Optimierung 1. Optimierung: einzelner Baum 2. Optimierung: Ast
  • Basisklasse1
    • Klasse1
    • Klasse2
    • Klasse3
  • Basisklasse2
    • Klasse1
    • Klasse2
    • Klasse3
  • Basisklasse3
    • Basisklasse3_Klasse1
    • Basisklasse3_Klasse2
    • Basisklasse3_Klasse3
  • Basisklasse1
    • Klasse1
    • Klasse2
    • Klasse3
  • Basisklasse2
    • Klasse1
    • Klasse2
    • Klasse3
  • Basisklasse3
    • Basisklasse3_Klasse1
    • Basisklasse3_Klasse2
    • Basisklasse3_Klasse3
  • Basisklasse PEAR
    • Basisklasse1
      • Klasse1
      • Klasse2
      • Klasse3
    • Basisklasse2
      • Klasse1
      • Klasse2
      • Klasse3
    • Basisklasse3
      • Basisklasse3_Klasse1
      • Basisklasse3_Klasse2
      • Basisklasse3_Klasse3
Es ergibt sich folgender Programmablauf:

  1. Preparse zur Ermittlung der Klassenbäume
  2. Kleinstmögliche Einheit parsen, analysieren und exportieren
  3. Nach Bearbeitung einer Einheit Daten für die Indexlisten speichern
  4. Warnmeldungen als Report speichern
  5. XML-Dokumente einlesen und in einem anderen Format ausgeben

Ausblick

PHPDoc formuliert einen ersten Vorschlag für ein einheitliches Dokumentationssystem in PHP. Es zeigt Wege für prozedualen und objektorientierten Code auf, liefert eine angemessene Tagliste und erschließt mit dem universellen Datenaustauschformat XML eine Vielzahl von Ausgabeformaten.

Die Schwächen des einfachen "Parsers" werden von der Tatsache aufgehoben, daß ein Rahmen für ein zukünftiges Dokumentationssystem vorgestellt wird. Wichtiger als die baldige Anbindung an den PHP-Parser ist der Aufbau weiterer Features und Tools rund um PHPDoc.

Eine grafische Oberfläche zur Verfeinerung der Dokumentation und zur Erstellung mehrsprachiger Dokumentationen erscheint sinnvoll, ebenso die Bereitstellung weiterer "Renderer" und Verbesserungen im Bereich der Übersichtsseiten.

© 2000, Ulf Wendel