Oebe Rombout

Als PHP/ASP/.NET programmeur heb je het waarschijnlijk al vaker meegemaakt: Je vindt een mooie class die precies kan wat jij wilt. Maar hoe krijg je hem aan de praat? Je gaat op zoek naar documentatie over de class en vindt een redelijk stuk over de class. Maar wat blijkt: de documentatie is van een oudere versie van de class. Voorbeelden kloppen niet meer, er zijn methoden bij gekomen en de parameters van methoden zijn veranderd.
Uiteraard kom je daar pas na een paar uur achter.

php-help-rescue

Documentatie

Het bijhouden van documentatie is een lastig werkje en wordt door veel programmeurs niet als ‘leuk’ ervaren. De documentatie die in de class verwerkt wordt is vaak nog wel redelijk van kwaliteit, maar een goed voorbeeld en een volledige overzicht van alle documentatie ontbreekt vaak.

Gelukkig bestaat er zoiets als een automatische-documentatie-generator. phpDocumentor is daar een voorbeeld van . phpdocumentor leest het commentaar dat programmeurs bij de classes en methods hebben gezet, indexeert alle methods en genereert een html-bestand met documentatie.
Drie nadelen:

  1. Je moet phpDocumentor hebben geïnstalleerd en geconfigureerd
  2. Je moet de generator regelmatig laten ‘draaien’ (evt. via cronjob – maar dat is niet voor iedereen bekend)
  3. Je documentatie komt ‘ergens’ op een webpagina te staan. De ‘link’ met de class is vaak weg.

De oplossing lag klaar bij Linux

Ik was al een tijdje op zoek naar een oplossing voor dit probleem. Op een gegeven moment was ik  in de Linux command-line met Subversion bezig en vond ik het antwoord:

Als je in Linux iets niet snapt, doe je ‘–help’ waarna je het antwoord krijgt. Bv.:

dev:~# svn add --help

geeft:

dev:~# svn add --help
add: Put files and directories under version control, scheduling
them for addition to repository.  They will be added in next commit.
usage: add PATH...

Valid options:
-N [--non-recursive]     : operate on single directory only
-q [--quiet]             : print as little as possible

.. en zo zou dat bij PHP ook zo moeten werken! De Help()-functie is geboren.

De Help()-functie is geboren

In elke php class zou een help-functie toegevoegd moeten worden. Dan zou het als volgt werken:

$o = new Utils_Email();
// als je iets even niet weet, roep je de Help-functie aan
$o->Help();

Vervolgens refresh je je browser en deze geeft als output in je scherm:

/**
* Class for sending e-mail messages.
*
* $oEmail = new Utils_Email();
* $oEmail->SetRecipient('info@test.nl', 'Occhio Web Development');
* $oEmail->SetSender('oebe@test.nl', 'Oebe Rombout');
* $oEmail->SetSubject('end my subscription');
* $oEmail->SetBody('I would like to end my subscription etc...');
* $oEmail->Send();
*
* @copyright  2010 Occhio bv
* @author     Oebe Rombout
* @version    $Rev 300$
*/
=== Public methods from class Utils_Email ===
/**
* Set the receiver of the e-mail
*
* Example of usage:
*   $oEmail->SetRecipient("oebe@test.nl");
*   $oEmail->SetRecipient("oebe@test.nl", "Rombout, Oebe");
*
* @param  string  $email      E-mail address of the recipient
* @param  string  $fullName   Fullname of the recipient (optional)
* @return void
*/
SetRecipient($email, $fullName)
/**
* Set the subject of the e-mail
*
* @param  string  $value   Subject of the e-mail
* @return void
*/
SetSubject($value)
etc

php-help-functie

Hoe werkt het? Reflection-class

PHP heeft sinds enkele jaren de Reflection-class (phpDocumentor maakt daar ook gebruik van). Hiermee kan je o.a. een class ‘onderzoeken’. Zo kan je van een class opvragen welke methods hij heeft, maar kan je ook het commentaar opvragen.
De output van de Help-functie hoef je dus niet zelf te schrijven. Het wordt gegenereerd uit het commentaar dat je al bij de class en methods gezet hebt. Geen dubbel werk dus.
Daarbij kan je nog allemaal handige dingen toevoegen:

Op deze manier creëer je een class die tevens zichzelf kan ‘uitleggen’. Code en documentatie op één plek; bij Linux werkt het al jaren.

Als je nog meer goede ideeën voor deze Help-class hebt, mail ze me dan.

Code voorbeelden

De method die je in elke class (of superclass daarvan) moet toevoegen:

public function Help()
	{
		$file = __FILE__;
		$class = __CLASS__;
		$className = get_class($this);

		// get comment of class
		$reflectClass = new ReflectionClass($class);
		$classDocComment =  $reflectClass->getDocComment();

		$help = <<<EOHTML
Help-functie van de {$class}-class in {$file}.
<pre>
{$classDocComment}

=== Public methods from class {$className} ===

EOHTML;

		echo $help;

		// Read public methods from class
		Odc_System_Utils_Reflection::GetPublicMethods($this);

		exit;
	}
 

De class die een lijst met public methods genereerd:

/**
 * @filesource
 * @package		Utils
 */

/**
 * Show handy data of Classes
 *
 * Example:

	public function Help()
	{
		$file = __FILE__;
		$class = __CLASS__;
		$className = get_class($this);

		$help = <<<EOHTML
Help-functie van de {$class}-class.
EOHTML;

		$methodsList = implode("\n- " , get_class_methods($this));

		// get comment of GenericObject-class
		$reflectClass = new ReflectionClass(__CLASS__);
		$goComment =  $reflectClass->getDocComment();

		$help .= <<<EOHTML
<pre>
$goComment

=== Public methods read from class {$className} ===

EOHTML;

		echo $help;
		Odc_System_Reflection::GetPublicMethods($this);

		exit;
	}

 * @author      Oebe Rombout
 * @copyright   2009 Occhio Design
 * @package     Utils
 */

class Odc_System_Utils_Reflection
{

	/**
	* Get names of the public methods of this class, to display in Help()
	*/
	function GetPublicMethods($oThis) {
		// Init the return array
		 $returnArray = array();

		 // Iterate through each method in the class
		 foreach (get_class_methods($oThis) as $method) {

			// Get a reflection object for the class method
			$reflect = new ReflectionMethod($oThis, $method);

			// For private, use isPrivate(). For protected, use isProtected()
			// See the Reflection API documentation for more definitions
			if($reflect->isPublic()) {

				// Skip deprecated methods
				if (strpos($reflect->getDocComment(), '@deprecated')) {
					continue;
				}
				//$reflect->export($oThis, $method);

				echo str_replace("\t", "", $reflect->getDocComment());

				// make list of parameters
				$aParameters = array();
				foreach ($reflect->getParameters() as $oReflectionParameter) {
					$aParameters[] = '$' . $oReflectionParameter->getName();
				}
				$parameters = implode(', ', $aParameters);
				echo "\n" .  $method . "($parameters)\n\n";

				// The method is one we're looking for, push it onto the return array
				array_push($returnArray,$method);
			}
		}
		// return the array to the caller
		return $returnArray;
	}

	public function Help()
	{
		$file = __FILE__;
		$class = __CLASS__;
		$className = get_class(self);

		$help = <<<EOHTML
Help-functie van de {$class}-class.
EOHTML;

		$methodsList = implode("\n- " , get_class_methods($this));

		// get comment of GenericObject-class
		$reflectClass = new ReflectionClass(__CLASS__);
		$goComment =  $reflectClass->getDocComment();

		$help .= <<<EOHTML
<pre>
$goComment

=== Public methods read from class {$className} ===

EOHTML;

		echo $help;
		Odc_System_Reflection::GetPublicMethods(self);

		exit;
	}
}

trackback url van deze post

Geen reacties

Plaats een reactie