Kontakt
Telefon +49 2161 17 58 83
Mobil +49 179 72 66 112
E-Mail info@ulrich-borchers.de

Webservice ersetzt bald PHPDoc? (Teil 2)

Im ersten Teil dieser Artikelserie über den ClassDescriptor hatte ich ein Konzept für die agile Live-Dokumentation von Quellcode vorgestellt.

Die Idee dabei ist es, Dokumentation von Quellcode on demand über einen Webservice auszuliefern: Der Server (Webservice) verfügt über den zu dokumentierenden Quellcode und kann via Reflection in den Code hineinschauen und sämtliche Strukturinformationen an Clients ausliefern.

Vorteile:

  • Kein Warten auf den Build-Prozess
  • Dokumentation im Standardformat (XML)
  • Die Dokumentation ist Programmiersprachen-übergreifend
  • Transformation in beliebige Dokumentationsformate möglich
  • Integration in IDEs möglich
  • Kein sensibler Quellcode auf dem Client
  • Dokumentation selektiv für bestimmte Revisionen (Tags, Branches) abrufbar


Um zu zeigen, wie leichtgewichtig - aber auch mächtig - der Ansatz ist, möchte ich in diesem zweiten Artikel zuerst eine Beispielklasse vorstellen, anhand der ich anschließend zeige, welche Daten ClassDescriptor für die einzelnen Methoden der Schnittstelle zurückliefert.

Die vom ClassDescriptor im Folgenden automatisch dokumentierte Beispielklasse implementiert ein Interface, hat mehrere Eigenschaften (public, protected, private, eine davon statisch). Außerdem besitzt die Klasse sowohl einen Konstruktor, als auch einen Destruktor, sowie mehrere Methoden, die public oder protected sind.

Ein Client, der die vollständige Beschreibung abruft:

require_once 'bootstrap.php';
require_once 'ClassDescriptor/SOAPClient.php';
require_once 'Dump.php';

$service_location = 'http://www.example.com/class_descriptor/server.php';

// class to describe. NOT included, client does not have it!
$classname = 'SomeGuy';

$client = new ClassDescriptor_SOAPClient($service_location);

try {
    $xml = $client->desc_complete($classname);
    Dump::response($xml, $client, 'xml');
}
catch (Exception $e) {
  echo $e->getMessage(), "\n";
}

Die vollständige Rückgabe des Webservice im XML-Format ist hier zu sehen.

Ein Teil dieser Rückgabe beschreibt die Struktur der Klasse:

<ClassDescriptor>
<class is_abstract="0" is_final="0" is_interface="0" is_iteraeable="0" has_constructor="1" has_destructor="1" has_parent_class="0">
<name>SomeGuy</name>
<phpdoc><![CDATA[/**
 * Not much to say here.
 *
 * @todo FIX VULNERABILITY ASAP: Don't offer public setters for $wife and $purse
 */]]></phpdoc>
 <interfaces>
 <interface>Rayable</interface>
 </interfaces>
 <properties />
 </class>
 <methods />
</ClassDescriptor>

Darin enthaltenen Informationen:

  • Name der Klasse: SomeGuy
  • ist abstrakt: nein
  • ist final: nein
  • ist Interface: nein
  • ist iterierbar: nein
  • hat einen Konstruktor: ja
  • hat einen Destruktor: ja
  • ist abgeleitet von einer anderen Klasse: nein (falls ja, enthielte die Rückgabe den Namen der Basisklasse)
  • PHPDoc-Block, der zur Klasse gehört
  • Implementierte Interfaces: Rayable
  • PHPDoc-Block der Klasse

Eigenschaften (properties) und Konstanten der Klasse:

<class>
    <properties>
        <property is_static="1">
            <name>heartbeat</name>
            <access>protected</access>
            <declaring_class>SomeGuy</declaring_class>
        </property>
        <property is_static="0">
            <name>purse</name>
            <access>private</access>
            <declaring_class>SomeGuy</declaring_class>
        </property>
        <property is_static="0">
            <name>wife</name>
            <access>protected</access>
            <declaring_class>SomeGuy</declaring_class>
        </property>
        <property is_static="0">
            <name>face</name>
            <access>public</access>
            <declaring_class>SomeGuy</declaring_class>
        </property>
        <property is_static="0">
            <name>likesToShowOff</name>
            <access>private</access>
            <declaring_class>SomeGuy</declaring_class>
        </property>
        <property is_static="0">
            <name>dirty</name>
            <access>private</access>
            <declaring_class>SomeGuy</declaring_class>
        </property>
    </properties>
    <constants/>
</class>

Es werden sechs property-Knoten für die sechs Eigenschaften der Klasse ausgegeben.

Zu jeder Eigenschaft ist aufgeführt, von welcher Klasse sie deklariert wird (declaring_class) - public- und protected-Eigenschaften können schließlich auch von einer Basisklasse stammen.

Die Eigenschaft "heartbeat" ist statisch (is_static="1"). Außerdem ist zu jeder Eigenschaft deren Name (name) und deren Sichtbarkeit (access) enthalten.

Methoden der Klasse:

<methods count_total="8" count_public="6" count_protected="2" count_private="0" count_static="0" count_final="0" count_abstract="0">

	<method is_static="0" is_final="0" is_abstract="0">
		<name>__construct</name>
		<access>public</access>
		<declaring_class>SomeGuy</declaring_class>
		<phpdoc><![CDATA[/**
		    * @param bool $likesToShowOff
		    */]]>
		</phpdoc>
		<params count="1" count_required="0">
			<param is_passed_by_reference="0" is_array="0" allows_null="1" is_optional="1" is_default_value_available="1" default_value="" position="0">
				<name>likesToShowOff</name>
			</param>
		</params>
	</method>
			
	<method is_static="0" is_final="0" is_abstract="0">
		<name>xray</name>
		<access>public</access>
		<declaring_class>SomeGuy</declaring_class>
		<phpdoc><![CDATA[/**
		    * @return string
		    */]]></phpdoc>
		<params count="0" count_required="0"/>
	</method>

	<method is_static="0" is_final="0" is_abstract="0">
		<name>isNaive</name>
		<access>protected</access>
		<declaring_class>SomeGuy</declaring_class>
		<params count="0" count_required="0"/>
	</method>

	<method is_static="0" is_final="0" is_abstract="0">
		<name>setPurse</name>
		<access>public</access>
		<declaring_class>SomeGuy</declaring_class>
		<phpdoc><![CDATA[/**
		     * @param float $purse
		     */]]>
		</phpdoc>
		<params count="1" count_required="1">
			<param is_passed_by_reference="0" is_array="0" allows_null="1" is_optional="0" is_default_value_available="0" default_value="" position="0">
				<name>purse</name>
			</param>
		</params>
	</method>

	<method is_static="0" is_final="0" is_abstract="0">
		<name>setWife</name>
		<access>public</access>
		<declaring_class>SomeGuy</declaring_class>
		<phpdoc><![CDATA[/**
		     * @param string $wife
		     */]]>
		</phpdoc>
		<params count="1" count_required="1">
			<param is_passed_by_reference="0" is_array="0" allows_null="1" is_optional="0" is_default_value_available="0" default_value="" position="0">
				<name>wife</name>
			</param>
		</params>
	</method>

	<method is_static="0" is_final="0" is_abstract="0">
		<name>setFace</name>
		<access>public</access>
		<declaring_class>SomeGuy</declaring_class>
		<phpdoc><![CDATA[/**
		     * @param array $face
		     */]]></phpdoc>
		<params count="1" count_required="1">
			<param is_passed_by_reference="0" is_array="1" allows_null="0" is_optional="0" is_default_value_available="0" default_value="" position="0">
				<name>face</name>
			</param>
		</params>
	</method>

	<method is_static="0" is_final="0" is_abstract="0">
		<name>laugh</name>
		<access>protected</access>
		<declaring_class>SomeGuy</declaring_class>
		<params count="0" count_required="0"/>
	</method>

	<method is_static="0" is_final="0" is_abstract="0">
		<name>__destruct</name>
		<access>public</access>
		<declaring_class>SomeGuy</declaring_class>
		<params count="0" count_required="0"/>
	</method>

</methods>

Da die Klasse acht Methoden besitzt, enthält die XML-Rückgabe acht method-Knoten.

Zu jeder Methode ist angegeben, ob sie statisch (is_static), final (is_final) und/oder abstrakt (is_abstract) ist.

Weiterhin sind Name der Methode (name), Sichtbarkeit (access) und die deklarierende Klasse (declaring_class) Teil der XML-Rückgabe. Außerdem ist der zur Methode gehörenden PHPDoc-Block enthalten (phpdoc).

Schließlich enthält jeder method-Knoten alle Parameter der Methode. Die Parameter sind wiederum mit sämtlichen, verfügbaren Details angegeben.

Fortsetzung ...

Im dritten und letzten Teil der Artikelserie über den ClassDescriptor werde ich - wie angekündigt - auf die Funktionsweise des Webservice eingehen. Dabei werde ich die Implementierung des Interface über SOAP zeigen. Außerdem wird es Codeauszüge zu sehen geben, die zeigen, wie die Codeanalyse über Reflection realisiert ist und wie daraus die standardisierte XML-Rückgabe erzeugt wird. Abschließend werde ich den Quellcode zum Download bereit stellen.

Zurück

Hands On PHP

Harter Hut

Programmiertes - Jenseits von Prosa.

Zend Certified Engineer
Zend Certified Engineer ZF
Oracle Certified Professional, MySQL 5.6 Developer
Sun Certified Java Programmer (SCJP)
Sun Certified Web Component Developer (SCWCD)
RSS
tl_files/open_clip_art/symbole/rss-icon.png  Abonnieren