PearCodingStandard

PEAR Coding Standard

Coding Style Index?

1.  Einrückungen und Zeilenlänge

Benutzen Sie Einrückungen mit 4 Leerzeichen, keine Tabulatoren. Damit helfen Sie, Probleme zu vermeiden, die mit Diffs, Patches und anderen CVS-Funktionen entstehen.

Wir empfehlen einen Zeilenumbruch bei ca. 75 - 85 Zeichen durchzuführen, um die Lesbarkeit zu erhöhen.

2.  Kontrollstrukturen (if, for, while, switch usw.)

Bsp für if-Kosntruktionen:

  1. <?php
  2. if ((condition1) || (condition2)) {
  3.     action1;
  4. } elseif ((condition3) && (condition4)) {
  5.     action2;
  6. } else {
  7.     defaultaction;
  8. }
  9. ?>

Kontroll-Ausdrücke sollten ein Leerzeichen zwischen den Schlüsselwörtern und der öffnenden Klammer haben, um sie von Funktionsaufrufen unterscheiden zu können.

Sie sollten unbedingt geschweifte Klammern verwenden, auch wenn sie technisch nur optional sind. Damit verbessern Sie die Lesbarkeit und vermeiden logische Fehler, wenn neue Zeilen hinzugefügt werden.

Bsp für switch-Ausdrücke:

  1. <?php
  2. switch (condition) {
  3. case 1:
  4.     action1;
  5.     break;
  6.  
  7. case 2:
  8.     action2;
  9.     break;
  10.  
  11. default:
  12.     defaultaction;
  13.     break;
  14. }
  15. ?>

3.  Funktionsaufrufe

Funktionen sollten ohne Leerzeichen zwischen dem Funktionsnamen, der öffnenden Klammer und dem ersten Parameter aufgerufen werden. Leerzeichen sollten gesetzt werden zwischen Komma und jedem Parameter. Zwischen dem letzten Parameter, der schliessenden Klammer und Semikolon sollten keine Leerzeichen gesetzt werden.

Beispiel:

  1. <?php
  2. $var = foo($bar, $baz, $quux);
  3. ?>

Wie oben gezeigt, sollte ein Leerzeichen vor und hinter das Gleichheitszeichen gesetzt werden, wenn der Rückgabewert der Funktion einer Variable zugewiesen wird. Wenn ein Block zusammenhängender Zuweisungen durchgeführt wird, empfehlen wir mehrere Leerzeichen einzufügen, um die Lesbarkeit zu verbessern:

  1. <?php
  2. $short         = foo($bar);
  3. $long_variable = foo($baz);
  4. ?>

4.  Klassen-Definition

Die öffnende Klammer einer Klassen-Deklaration beginnt auf einer neuen Zeile:

  1. <?php
  2. class FooBar
  3. {
  4.  
  5.     //... ihr Code
  6.  
  7. }
  8. ?>

5.  Funktionsdefinitionen

Funktionsdeklarationen folgen dem „K&R-Stil“ (Programmierstil der C-Erfindern Brian W. Kernighan und Dennis Ritchie):

  1. <?php
  2. function fooFunction($arg1, $arg2 = '')
  3. {
  4.     if (condition) {
  5.         statement;
  6.     }
  7.     return $val;
  8. }
  9. ?>

Argumente mit Standardwerten werden am Ende der Argumentenliste platziert. Eine Funktion sollte immer einen aussagekräftigen Wert zurückliefern, soweit wie es möglich ist.

Beispiel:

  1. <?php
  2. function connect(&$dsn, $persistent = false)
  3. {
  4.     if (is_array($dsn)) {
  5.         $dsninfo = &$dsn;
  6.     } else {
  7.         $dsninfo = DB::parseDSN($dsn);
  8.     }
  9.  
  10.     if (!$dsninfo || !$dsninfo['phptype']) {
  11.         return $this->raiseError();
  12.     }
  13.  
  14.     return true;
  15. }
  16. ?>

6.  Kommentare

Sie müssen vollständige Inline-Dokumentation bereitstellen (Docblocks).

Sie sollten auch abseits der offziellen API-Dokumentation Kommentare im Quellcode einsetzen. Als Daumenregel gilt, wenn Sie auf einen Code-Abschnitt schauen und denken: „Wow, Ich würde nicht versuchen herauszufinden, wie es funktioniert“, sollten Sie auf jeden Fall einen Kommentar ergänzen, bevor Sie vergessen, wie es funktioniert.

Kommentare im C-Stil (/* */) und von Standard-C++ (//) sollten verwendet werden. Kommentare im Perl/shell-Stil (#) sollten Sie vermeiden.

7.  Code einbinden

Immer wenn Sie eine Klassendatei unbedingt inkludieren müssen, dann benutzen Sie require_once. Benötigen Sie hingegen eine Datei nur bedingt, z.B. in Factory-Methoden, verwenden Sie include_once. Beide stellen sicher, dass die Datei nur einmal eingebunden wird. Beide Funktionen benutzen die gleiche Liste zur Verwaltung der bereits eingebundenen Dateien. Sie müssen sich über eine Mischung aus beiden Funktionsaufrufen keine Gedanken machen - eine Datei, die per require_once eingebunden wurde, wird nicht erneut eingebunden mit include_once.

Anmerkung: include_once und require_once sind Anweisungen, nicht Funktionen. Deshalb sollten die Dateinamen nicht in Klammern eingeschlossen werden.

8.  PHP-Code-Tags

Benutzen Sie immer <?php ?> um Ihren PHP-Code zu markieren, niemale die Kurzform <? ?>. Die erste Variante funktioniert unabhängig vom Betriebssystem und der PHP-Konfiguration.

9.  Kopf-Kommentare

Alle Quellcode-Dateien sollen einen „Page-level“ Docblock am Datei-Anfang besitzen und einen „Class-level“ Docblock unmittelbar vor jeder Klasse.

Beispiele:

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6. * Short description for file
  7. *
  8. * Long description for file (if any)...
  9. *
  10. * PHP versions 4 and 5
  11. *
  12. * LICENSE: This source file is subject to version 3.0 of the PHP license
  13. * that is available through the world-wide-web at the following URI:
  14. * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  15. * the PHP License and are unable to obtain it through the web, please
  16. * send a note to license@php.net so we can mail you a copy immediately.
  17. *
  18. * @category   CategoryName
  19. * @package    PackageName
  20. * @author     Original Author <author@example.com>
  21. * @author     Another Author <another@example.com>
  22. * @copyright  1997-2005 The PHP Group
  23. * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24. * @version    CVS: $Id:$
  25. * @link       http://pear.php.net/package/PackageName
  26. * @see        NetOther, Net_Sample::Net_Sample()
  27. * @since      File available since Release 1.2.0
  28. * @deprecated File deprecated in Release 2.0.0
  29. */
  30.  
  31. /*
  32. * Place includes, constant defines and $_GLOBAL settings here.
  33. * Make sure they have appropriate docblocks to avoid phpDocumentor
  34. * construing they are documented by the page-level docblock.
  35. */
  36.  
  37. /**
  38. * Short description for class
  39. *
  40. * Long description for class (if any)...
  41. *
  42. * @category   CategoryName
  43. * @package    PackageName
  44. * @author     Original Author <author@example.com>
  45. * @author     Another Author <another@example.com>
  46. * @copyright  1997-2005 The PHP Group
  47. * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  48. * @version    Release: @package_version@
  49. * @link       http://pear.php.net/package/PackageName
  50. * @see        NetOther, Net_Sample::Net_Sample()
  51. * @since      Class available since Release 1.2.0
  52. * @deprecated Class deprecated in Release 2.0.0
  53. */
  54. class Foo_Bar
  55. {
  56. }
  57.  
  58. ?>

9.1  Erforderliche Tags

Kurzbeschriebung

Die Kurzbeschreibung muss in allen Docblocks existieren. Sie umfasst einen Satz, und sollten keinesfalls nur aus dem Namen des beschreibenden Objektes stehen.

PHP Version

Folgende Zeile muss in den Page-level-Docblock eingefügt werden. Sie beschreibt, unter welcher PHP-Version der Quellcode läuft:

  • PHP version 4
  • PHP version 5
  • PHP versions 4 and 5

@license

Sie können verschiedene Lizenzen für ihr Package verwenden. Sie müssen eine auswählen und diese sowohl im Page-level-, wie auch dem Class-level-Docblock einfügen:

@link

Die Link-Angabe muss im Page-level- and Class-level-Docblock erfolgen. Sie müssen den Eintrag für „PackageName“ natürlich durch den Namen Ihres Packages ersetzen. Auf diese Weise ist sicher gestellt, dass die API-Dokumentation die Links auf die Package-Homepage enthält.

@author

Es gibt keine klare Regel, wann jemand zur Liste der Quellcode-Autoren hinzugefügt werden sollte. Allgemein sollten sie substanziell beigetragen haben, ca. 10% bis 20% des Codes. Sie können Ausnahmen machen, wenn Methoden neu geschrieben wurden oder neue Logik beigesteuert wurde.

Einfache Code-Neuformatierungen oder Bug-Fixes sollten nicht zur Aufnahme in die Liste führen.

@since

Dieses Tag ist erforderlich, wenn eine Datei oder Klasse nach dem ersten Release zum Package ergänzt wurde. Verwenden Sie es nicht beim ersten Release.

@deprecated

Dieses Tag ist erforderlich, wenn eine Datei oder Klasse nicht mehr benutzt wird, aber für die Rückwärtskompatibilität noch verfügbar ist.

9.2  Optionale Tags

@copyright

Sie können dieses Tag setzen, wenn Sie Copyright-Anmerkungen ergänzen wollen. Das Format des Tags: Die vierstellige Jahreszahl bzw. bei mehreren Jahren, nur das erste und letzte Jahr getrennt mit einem Querstrich; danach der Copyright-Inhaber, also die betreffenden Personen, Firma oder z.B. die PHP Group.

Beispiele:

  • @copyright 2003 John Doe and Jennifer Buck
  • @copyright 2001-2004 John Doe
  • @copyright 1997-2004 The PHP Group
  • @copyright 2001-2004 XYZ Corporation

License Summary

If you are using the PHP License, use the summary text provided above. If another license is being used, please remove the PHP License summary. Feel free to substitute it with text appropriate to your license, though to keep things easy to locate, please preface the text with LICENSE: .

@see

Fügen Sie ein @see-Tag hinzu, wenn Sie auf andere Abschnitte in der Package-Dokumentation verweisen. Wenn Sie mehrere Einträge hinzufügen, verwenden Sie nicht mehrere Tags, sondern trennen diese in einem Tag per Komma.

Abfolge und Leerzeichen

Um die langfristige Lesbarkeit zu gewährleisten, sollten Texte und Tags dem gegebenem Beispiel folgen. Diese Festlegungen entsprechen dem JavaDoc-Standard.

Verwendung von @package_version@

Es gibt zwei Wege @package_version@ zu ersetzen. Das ist abhängig davon, ob Sie die Package-Datei package.xml von Hand erzeugen oder das Package PackageFileManager benutzen.

Wenn Sie die Datei direkt bearbeiten, ergänzen Sie ein <replace>-Tag für jede Datei. Das XML sieht dann ähnlich wie dieses aus:

  1. <file name="Class.php">
  2.   <replace from="@package_version@" to="version" type="package-info" />
  3. </file>

Wenn PackageFileManager verwenden, rufen Sie addReplacement() für jede Datei auf:

  1. <?php
  2. $pkg->addReplacement('filename.php', 'package-info',
  3.                      '@package_version@', 'version');
  4. ?>

9.3  Übergangsregeln

Für existierende kleine Packages

Existierende Packages mit nur wenigen Dateien sollten die DocBlöcke im nächst möglichen Release enthalten.

Für existierende große Packages

Existierende Packages mit vielen Dateien sollten die neuen DocBlöcke sobald wie möglich integrieren. Auf jeden Fall aber mit den nächsten Major-Release.

Neue und unveröffentliche Packages

Neue Packages und existierende Package, für welche noch kein Release existiert, müssen über die DocBlöcke verfügen, wenn ihr erstes Release erscheint.

10.  CVS-Nutzung

Ergänzen Sie das $Id$-CVS-Schlüsselwort in jeder Datei.

11.  Beispiel-URLs

Benutzen Sie example.com, example.org und example.net für alle Beispiel-URLs und Email-Adressen entsprechend RFC 2606.

12.  Namens-Konventionen

Klassen

Verwenden Sie beschreibende Klassennamen und vermeiden Sie Abkürzungen. Klassennamen beginnen immer mit einen Großbuchstaben. Die Klassenhierarchie in PEAR spiegelt sich auch im Klassennamen wieder, jede Ebene der Hierarchie wird durch einen einzelnen Unterstrich getrennt.

Beispiele für Klassennamen:

  • Log
  • Net_Finger
  • HTML_Upload_Error

Funktionen und Methoden

Funktionen und Methoden sollten dem „Studly Caps“-Stil folgen (auch bekannt als „Bumpy Base“ oder „Camel Caps“). Funktionsnamen sollte der Package-Name vorangestellt werden, um Kollisionen mit anderen Funktionsnamen zu vermeiden. Der erste Buchstabe nach dem Prefix wird klein geschrieben, und jeder Buchstabe eines neuen „Wortes“ im Namen wird großgeschrieben.

Beispiele:

  • connect()
  • getData()
  • buildSomeWidget()
  • XML_RPC_serializeData()

Privaten Klassenelemente wird ein Unterstrich vorangestellt.

Zum Beispiel:

  • _sort()
  • _initTree()

$this->_status

Anmerkung: Unter PHP 5 gilt: Klassenelemente, welche protected sind, werden nicht mit einem Unterstrich versehen:

  • protected $somevar
  • protected function initTree()

12.1  Konstanten

Konstanten werden immer vollständig groß geschrieben, mit Unterstrichen zwischen den Worten. Ihre Namen müssen mit dem Klassen- bzw. Package-Namen beginnen. Zum Beispiel beginnen alle Konstanten des DB::-Packages mit DB_.

Anmerkung: Die Konstanten true, false und null werden als einzige Ausnahme immer klein geschrieben.

12.2  Globale Variablen

Wenn Ihr Package globale Variablen benötigt, sollte deren Name mit einem Unterstrich beginnen, gefolgt vom Package-Namen und einem weiteren Unterstrich. Zum Beispiel benutzt das PEAR-Package die globale Variable $_PEAR_destructor_object_list.

13.  Dateiformate

Alle Skripte in PEAR müssen:

  • als ASCII gespeichert werden.
  • mit dem Zeichensatz ISO-8859-1 kodiert werden.
  • den UNIX-Konventionen folgen. „Unix-Konventionen“ bedeutet:
    • Zeilen dürfen nur mit dem Line-Feed-Zeichen (LF) enden. Das Zeichen entspricht dem Ordinal-Wert 10, Octal 012 und hexadezimal 0A. Benutzen Sie kein Carriage-Return-Zeichen (CR) wie unter Apple Macintosh-Computern oder die CRLF-Kombination unter Windows.
    • Fügen Sie ein Zeilenende-Zeichen nach dem schliessendem PHP-Tag (?>) ein. Das bedeutet, der Cursor im Editor steht eine Zeile nach dem schliessendem Tag.

14.  E_STRICT-kompatibler Code

Jeder Code muss E_STRICT-kompatibel sein. Das heisst, er darf keine Fehler oder Warnungen erzeugen, wenn das Fehler-Reporting von PHP auf E_STRICT eingestellt ist.

Die Entwicklung existierender Packages, die dieser Konvention noch nicht entsprechen, müssen dies auch noch nicht. Erst wenn eine neue major-Version eines Packages erscheint, dann muss diese Version der E_STRICT-Konvention entsprechen.

15.  Richtlinen zur Fehlerbehandlung

15.1  Richtlinen zur Fehlerbehandlung

Dieser Abschnitt beschreibt wie Fehler in PEAR-Packages behandelt werden sollen, die für PHP 5 und 6 entwickelt werden. Fehler werden über Exceptions abgewickelt, sie wurden mit PHP 5.0 und der Zend Engine 2 eingeführt.

Was ist ein Fehler?

Ein Fehler ist definiert als ein unerwartet, nicht korrekter Programmzustande, der nicht wieder behoben werden kann. Zur Vereinfachung dieser Definition gilt, dass die Behebung des Fehlers nicht innerhalb einer Methode möglich ist. Eine unvollständige Behebung gilt trotzdem als Behebung.

Beispiel 4-1. Eine typische Fehlersituation

  1. <?php
  2. /**
  3. * Verbinde zur angegebenen Datenbank
  4. *
  5. * @throws Example_Datasource_Exception wenn der Verbindungsaufbau fehlschlägt
  6. */
  7. function connectDB($dsn) {
  8.     $this->db =& DB::connect($dsn);
  9.     if (DB::isError($this->db))
  10.     {
  11.         throw new Example_Datasource_Exception(
  12.                 "Unable to connect to $dsn:" . $this->db->getMessage()
  13.         );
  14.     }
  15. }
  16. ?>

In diesem Beispiel soll die Methode die Verbindung mit der Datenbank mit dem gegegebenem DSN herstellen. Die Methode ruft ihrerseits nur PEAR::DB, wenn dieses Package einen Fehler wirft, kann nur eine Exception erzeugt und geworfen werden, ohne weiter Einfluß nehmen zu können.

Beispiel 4-2. Fehlerbehandlung mit Behebung

  1. <?php
  2. /*
  3. * Verbinde mit einer der möglichen Datenbanken
  4. *
  5. * @throws Example_Datasource_Exception wenn keine der gewählten
  6. *         Datenbank angesprochen werden konnte.
  7. *
  8. * @throws Example_Config_Exception wenn keine Datenbanken
  9. *         konfiguriert wurden
  10. */
  11.  
  12. function connect(Config $conf)
  13. {
  14.     $dsns =& $conf->searchPath(array('config', 'db'));
  15.     if ($dsns === FALSE) throw new Example_Config_Exception(
  16.         'Unable to find config/db section in configuration.'
  17.     );
  18.  
  19.     $dsns =& $dsns->toArray();
  20.  
  21.     foreach($dsns as $dsn) {
  22.         try {
  23.             $this->connectDB($dsn);
  24.             return;
  25.         } catch (Example_Datasource_Exception e) {
  26.             // Warn-/Logging-Code um den Verbindungsfehler
  27.             // aufzuzeichnen
  28.         }
  29.     }
  30.     throw new Example_Datasource_Exception(
  31.         'Unable to connect to any of the configured databases'
  32.     );
  33. }
  34. ?>

Das zweite Beispiel zeigt, wie eine Exception empfangen und behandelt wird. Die verwendete connectDB()-Methode kann nur einen Fehler melden, wenn die Verbindung fehlschlägt. Die übergeordnete Methode connect() hingegen weiss, dass das Objekt auch mit einer der anderen Datenbank-Verbindungen lauffähig ist. Deshalb kann der Fehler als behoben angesehen werden und die Exception wird nicht weitergeleitet.

Beispiel 4-3. Unvollständige Behebung

  1. <?php
  2. /**
  3. * loadConfig wertet die angegebene Konfiguration aus. Wenn die
  4. * Konfiguration unkorrekt ist, dann wird auf die Standard-
  5. * zurückgegriffen
  6. *
  7. */
  8. function loadConfig(Config $conf)
  9. {
  10.     try {
  11.         $this->config = $conf->parse();
  12.     } catch (Config_Parse_Exception e) {
  13.         // Warn-/Logging-Code
  14.         // Unvollständige Fehlerbehebung
  15.         $this->config = $this->defaultConfig;
  16.     }
  17. }
  18. ?>

Die Fehlerbehebung führt zu Seiteneffekten, deshalb ist sie nicht vollständig. Das Programm kann weiterlaufen, die Exception gilt als behandelt und muss nicht weitergeleitet werden. Wie im vorherigen Beispiel sollte die aufgetretene Exception aber trotzdem geloggt werden oder eine andere Form der Warnung stattfinden.

Fehler-Benachrichtigung PHP 5 PEAR-Packages

Fehlerhafte Zustände in PEAR-Packages für PHP 5 müssen über Exceptions gemeldet werden. Nicht mehr verwendet werden sollten Fehlercodes oder ein PEAR_Error-Objekt. Diese Regel gilt natürlich nicht, wenn das Package kompatibel mit PHP 4 bleiben muss. In diesem Fall gelten die Konvention der PEAR Coding Standards unter PHP 4 weiter.

Eine Exception sollte immer geworfen werden, wenn ein fehlerhafter Zustand auftritt, entsprechend der Definition im vorherigen Abschnitt. Die geworfene Exception sollte genügend Informationen enthalten, um den Fehler debuggen zu können und schnell dessen Grund herauszufinden. Bedenken Sie, dass in Produktionsumgebungen keine Exception an den Endanwender durchdringen sollten. Deshalb muss man sich keine Gedanken machen über die Komplexität der Fehlermeldung.

Die Basis-Klasse PEAR_Exception enthält eine wörtliche Beschreibung des Fehlers, womit der Programmzustand beschrieben wird, der zum Fehler führte, und - optional - Execptions, die durch untergeordnete Programmaufrufe herbei geführten wurden und die ursprüngliche Ursache des Fehlers darstellen können.

Die Arten von Informationen die in einer Exception enthalten sein müssen, hängt von der Art des Fehlers ab. Es gibt drei Varianten von Exceptions:

  1. Fehler, die während der Vorabprüfung auftreten können.
  2. Fehler, die durch untergeordneten Bibliotheksaufrufe auftreten und durch Fehlercodes oder -Objekte signalisiert werden
  3. Nicht-korrigierbare Exceptions von untergeordneten Bibliotheken.

Fehler, die während der Vorabprüfung auftreten können, sollten eine Beschreibung der fehlgeschlagenen Prüfung enthalten. Wenn möglich sollte der fehlerhafte Wert mit angegeben werden.

Beispiel 4-4.

  1. <?php
  2. function divide($x, $y)
  3. {
  4.     if ($y == 0) {
  5.         throw new Example_Aritmetic_Exception('Division by zero');
  6.     }
  7. }
  8. ?>

Fehler, die durch untergeordneten Bibliotheksaufrufe auftreten und durch Fehlercodes oder -Objekte signalisiert werden, sollten in Exceptions umgewandelt werden, wenn diese nicht behoben werden können. Die Fehlerbeschreibung sollte die originale Fehlerinformationen enthalten bzw. entsprechend konvertiert werden. Am Beispiel der obigen connect()-Methode:

Beispiel 4-5.

  1. <?php
  2. /**
  3. * Verbinde zur angegebenen Datenbank
  4. *
  5. * @throws Example_Datasource_Exception wenn der Verbindungsaufbau fehlschlägt
  6. */
  7. function connectDB($dsn) {
  8.     $this->db =& DB::connect($dsn);
  9.     if (DB::isError($this->db)) {
  10.         throw new Example_Datasource_Exception(
  11.                 "Unable to connect to $dsn:" . $this->db->getMessage()
  12.         );
  13.     }
  14. }
  15. ?>

Nicht-korrigierbare Exceptions von untergeordneten Bibliotheken sollten weitergeleitet oder erneut geworfen werden. Wenn sie weitergeleitet werden soll, dann behandeln Sie die Exception nicht weiter. Wenn Sie die Exception erneut werfen, dann müssen Sie die originale Exception in der neuen Exception verpacken.

Beispiel 4-6. Eine Exception neu verpacken

  1. <?php
  2. function preTaxPrice($retailPrice, $taxRate)
  3. {
  4.     try {
  5.         return $this->divide($retailPrice, 1 + $taxRate);
  6.     } catch (Example_Aritmetic_Exception e) {
  7.         throw new Example_Tax_Exception('Invalid tax rate.', e);
  8.     }
  9. }
  10. ?>

Beispiel 4-7. Eine Exception weiterleiten

  1. <?php
  2. function preTaxPrice($retailPrice, $taxRate)
  3. {
  4.     return $this->divide($retailPrice, 1 + $taxRate);
  5. }
  6. ?>

Die Entscheidung, ob eine Exception neu verpackt oder weitergeleitet werden soll, ist eine Frage der Software-Architektur. Exceptions sollten weitergeleitet werden, ausser in zwei Fällen:

  1. Die originale Excpetion ist von einem anderen Package. Wenn diese weitergeleitet wird, dann würden Details der Implementierung nach aussen dringen.
  2. Die Methode kann nützliche Debug-Informationen ergänzen.

15.2  Exceptions und der normale Programmfluß

Exceptions sollten niemals als Bestandteil des normalen Programmflußes benutzt werden. Wenn alle Logik zur Behandlung von Exceptions entfernt würde (try-catch-Statements), dann sollte der verbliebende Code den "wahren Pfad" repräsentieren -- dem Programmfluß, wenn keinerlei Fehler auftreten würden.

Diese Forderung entspricht der Erwartung, dass Exceptions nur bei fehlerhaften Zuständen geworfen werden sollten und niemals bei regulären Zuständen.

Ein Beispiel für die falsche Benutzung der Exception-Weiterleitung ist die Rückgabe eines Wertes eines rekursiven Aufrufs:

Beispiel 4-8.

  1. <?php
  2. /**
  3. * Rekursive Suche in einem Baum nach einem String
  4. * @throws ResultException
  5. */
  6. public function search(TreeNode $node, $data) 
  7. {
  8.     if ($node->data === $data) {
  9.          throw new ResultException( $node );
  10.     } else {
  11.          search( $node->leftChild, $data );
  12.          search( $node->rightChild, $data );
  13.     }
  14. }
  15. ?>

Im Beispiel wird die ResultException benutzt, um "schnell" wieder aus der Rekursion heraus zu kommen. Das ist im Fehlerfall tatsächlich praktisch, in diesem Fall, aber nur ein Beispiel für einen faulen Programmierer. Die Klassen-Hierarchie von Exceptions

Alle Exceptions, die von Packages geworfen werden, müssen von PEAR_Exception abstammen. PEAR_Exception bietet zusätzliche Fähigkeiten, um andere Exceptions zu verpacken. Sie finden diese nicht in der obersten PHP Exception-Klasse, sind aber notwendig, um die oben gestellten Anforderungen zu erfüllen.

Zusätzlich sollte jedes PEAR-Package seine eigene Exception-Klasse definieren; der Name der Klasse entspricht dem Muster: <Package_Name>_Exception. Jede Exception sollte von dieser Klasse abgeleitet werden. Exceptions dokumentieren

Da PHP, im Gegensatz zu Java, es nicht erfordert, mögliche Exceptions in der Funktionssignatur aufzunehmen, ist deren sorgfältige Dokumentation im Methodenkopf wichtig.

Beispiel 4-9. Exceptions werden dokumentiert mit dem @throws-Schlüsselwort

  1. <?php
  2. /**
  3. * Diese Methode sucht nach Aliens.
  4. *
  5. * @return array Array von Alien-Objekten.
  6. * @throws AntennaBrokenException wenn die Impedanz-Leser anzeigt, dass die
  7. *         Antenne nicht funktioniert
  8. *
  9. * @throws AntennaInUseException wenn ein anderer Prozess die Antenne
  10. *         bereits benutzt
  11. */
  12. public function findAliens($color = 'green');
  13. ?>

In vielen Fällen wandelt die mittlere Schicht einer Anwendung Exceptions von untergeordneten Methoden in aussagekräftiger, anwendungsspezifische Exceptions. Das sollte ebenfalls angesprochen werden:

Beispiel 4-10.

  1. <?php
  2. /**
  3. * Lade Session-Objekte in den Shared-Memory
  4. *
  5. * @throws LoadingException Jede untergeordnete IOException wird als
  6. *         LoadingException neu verpackt.
  7. */
  8. public function loadSessionObjects();
  9. ?>

In anderen Fällen kann ihre Methode als Filter fungieren, der nur bestimmte Exceptions weiterleitet. Dann sollten Sie dokumentieren, welche Exceptions nicht von Ihrer Methode abgefangen werden.

Beispiel 4-11.

  1. <?php
  2. /**
  3. * Führt eine Reihe von Datenbankanfragen aus (atomar, nicht innerhalb einer Transaktion).
  4. * @throws SQLException Low-level SQL-Fehler werden direkt weitergeleitet.
  5. */
  6. public function batchExecute();
  7. ?>

15.3  Exceptions als Teil der API

Exceptions spielen eine kritische Rolle in der API ihrer Bibliothek. Entwickler, die Ihre Bibliothek verwenden, sind abhängig von der angemessenen Beschreibung wo und warum Exceptions auftreten in Ihrem Package. Auch die sorgfältige Planung der Fehlermeldungen ist ein wichtiger Faktor für die Erhaltung der Rückwärts-Kompatibilität.

Da Exceptions ein integraler Bestandteil der API ihres Packages sind, darf bei Änderungen daran die Rückwärts-Kompatibilität (BC) nicht grundlos gebrochen werden.

Dinge, die zum Bruch führen:

  • Jede Änderung an Methoden, die Exceptions werfen.
  • Wenn eine Exception-Klasse verwendet wird, die höher in der Vererbungskette liegt, als die ursprüngliche. Zum Beispiel, wenn Sie in einer neueren Version eine PEAR_Exception werfen würden, in der alten aber z.B. PEAR_IOException verwendet haben.

Dinge, die nicht zum Bruch führen:

  • Wenn eine abgeleitete Klasse der originalen Exception verwendet wird. Zum Beispiel, wenn Sie in der aktuellen Version eine PEAR_IOException werfen, und in älteren Versionen PEAR_Exception. Natürlich nur unter der Voraussetzung, dass PEAR_IOException von PEAR_Exception) abgeleitet ist.

16.  Best practices

Es gibt einige andere Dinge, die nicht vom PEAR Coding Standard betroffen sind, sondern von den persönlichen Gewohnheiten abhängen und nicht die Lesbarkeit unmittelbar berühren. Das betrifft z.B. die Frage 'Einfache oder doppelte Anführungszeichen'. Es handelt sich um Konstrukte, welche die Programmierung vereinfachen ohne konkrete Probleme zu verursachsen. Welche dieser 'üblichen' Praktiken genutzt wird, diese Entscheidung ist dem Programmierer überlassen. Wichtiger ist die konsequente Anwendung der eigenen Entscheidung in einem Package. Respektieren Sie die Entscheidung des verantwortlichen Programmierers, wenn Sie fremde Packages verändern.

17.  Beispieldatei inklusive Docblock-Kommentaren

Der Quellcode von PEAR-Packages wird von tausenden von Menschen gelesen. Genauso kann es passieren, dass andere einmal an Ihrem Package entwicklen werden. Um es ihnen leichter zu machen, ist die Formatierung des Quellcode und der Docblöcke standarisiert. Damit können Andere Informationen einfacher finden, das sie wissen, wo sie suchen müssen.

Jeder Docblock im Beispiel enthält viele Details wie Sie die Kommentare schreiben sollten. Diese Instruktionen sind aus zwei Gründen wichtig. Erstens können Benutzer und Entwickler schneller verstehen, was Ihr Code tut. Zweitens wird auf der PEAR-Webseite die Quellcode-Dokumentation für jedes Release von jedem Package bereitgestellt und Sie sollten auch dafür sorgen, dass diese Möglichkeit sinnvoll genutzt werden kann.

Bitte achten Sie auch auf den Einsatz von vertikalen und horizontalen Leerräumen. Sie sind Bestandteil der Standards.

Die „Fold Markers“ (// {{{ und // }}}) sind optional. Wenn Sie nicht benötigt werden, entfernen Sie die Einstellung foldmethod=marker aus dem Block mit Vim-Einstellungen.

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6. * Kurze Beschreibung des Datei-Inhalts
  7. *
  8. * Lange Beschreibung des Datei-Inhaltes, wenn erforderlich.
  9. *
  10. * PHP versions 4 and 5
  11. *
  12. * LICENSE: This source file is subject to version 3.0 of the PHP license
  13. * that is available through the world-wide-web at the following URI:
  14. * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  15. * the PHP License and are unable to obtain it through the web, please
  16. * send a note to license@php.net so we can mail you a copy immediately.
  17. *
  18. * @category   CategoryName
  19. * @package    PackageName
  20. * @author     Original Author <author@example.com>
  21. * @author     Another Author <another@example.com>
  22. * @copyright  1997-2005 The PHP Group
  23. * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24. * @version    CVS: $Id:$
  25. * @link       http://pear.php.net/package/PackageName
  26. * @see        NetOther, Net_Sample::Net_Sample()
  27. * @since      File available since Release 1.2.0
  28. * @deprecated File deprecated in Release 2.0.0
  29. */
  30.  
  31. /**
  32. * Das ist ein "Docblock-Kommentar", auch bekannt als "docblock"/"Docblock"
  33. * Der Klassen-Docblock weiter unten enthält eine Beschreibung wie sie
  34. * geschrieben werden.
  35. */
  36. require_once 'PEAR.php';
  37.  
  38. // {{{ constants
  39.  
  40. /**
  41. * Methoden geben diesen Wert im Erfolgsfall zurück.
  42. */
  43. define('_NET_SAMPLE_OK', 1);
  44.  
  45. // }}}
  46. // {{{ GLOBALS
  47.  
  48. /**
  49. * Die Anzahl der erzeugten Objekte
  50. * @global int $GLOBALS['NET_SAMPLE_Count']
  51. */
  52. $GLOBALS['_NET_SAMPLE_Count'] = 0;
  53.  
  54. // }}}
  55. // {{{ Net_Sample
  56.  
  57. /**
  58. * Ein Beispiel wird Code entsprechend der PEAR-Standards aussieht
  59. *
  60. * Anmerkung des Übersetzers: Quelltext-Kommentare sollten natürlich
  61. * durchgängig in Englisch erfolgen!
  62. *
  63. * Ein Docblock-Kommentar beginnt mit "/**" am Anfang.  Beachten Sie, das "/"
  64. * beginnt mit der normalen Einrückung und die Sterne darunter stehen in der
  65. * selben Textspalte wie der erste Stern. Der letzte Zeile des Kommentar-Blocks
  66. * sollte unmittelbar das zu dokumentierende Element folgen,
  67. * Vermeiden Sie zusätzliche Leerzeilen. Ergänzen Sie eine Leerzeile
  68. * zwischen Absätzen im Kommentartext, genauso zwischen Kommentartext und dem
  69. * ersten @-Tag. Ein Zeilenumbruch im Kommentartext sollte nach 80 Zeichen
  70. * erfolgen.
  71. *
  72. * Docblöcke können nur für eine begrenzte Anzahl an Elementen verwendet
  73. * werden (Klassen, Eigenschaften, Methoden, Konstanten, Include und
  74. * globale Variablen. In der Dokumentation zu phpDocumentor finden Sie mehr
  75. * Informationen dazu:
  76. * http://phpdoc.org/docs/HTMLSmartyConverter/default/phpDocumentor/tutorial_phpDocumentor.howto.pkg.html
  77. *
  78. * Der Javadoc Style Guide ist eine exzellente Quelle wie man Kommentare
  79. * formulieren sollte. Letztlich sind diese Informationen eine Zusammenfassung
  80. * davon, andererseits gibt es aber auch einige Abweichungen davon.
  81. * http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#styleguide
  82. *
  83. * Diese erste Zeile jedes Docblocks ist eine Zusammenfassung. Sie sollte
  84. * genau einen Satz umfassen, ohne Punkt am Ende. Zusammenfassungen für
  85. * Klassen, Eigenschaften und Konstanten sollten nicht deren Namen enthalten
  86. *
  87. * Die unten aufgeführten Tag werden üblicherweise für Klassen benutzt.
  88. * Die Tags @category bis @version sind erforderlich. Die Übrigen
  89. * sollten ergänzt werden, wenn erforderlich. Verwenden Sie die Tags
  90. * in der Reihenfolge, wie hier aufgeführt. phpDocumentor bietet
  91. * weitere Tags, verwenden Sie diese, wenn erforderlich.
  92. *
  93. * @category   CategoryName
  94. * @package    PackageName
  95. * @author     Original Author <author@example.com>
  96. * @author     Another Author <another@example.com>
  97. * @copyright  1997-2005 The PHP Group
  98. * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  99. * @version    Release: @package_version@
  100. * @link       http://pear.php.net/package/PackageName
  101. * @see        NetOther, Net_Sample::Net_Sample()
  102. * @since      Class available since Release 1.2.0
  103. * @deprecated Class deprecated in Release 2.0.0
  104. */
  105. class Net_Sample
  106. {
  107.     // {{{ properties
  108.  
  109.     /**
  110.      * Der Zustand von foo's universe
  111.      *
  112.      * Potentielle Werte sind 'good', 'fair', 'poor' und 'unknown'.
  113.      *
  114.      * @var string
  115.      */
  116.     var $foo = 'unknown';
  117.  
  118.     /**
  119.      * The status of life
  120.      *
  121.      * Vergessen Sie nicht, dass private Elemente mit einem
  122.      * Unterstrich beginnen müssen.
  123.      *
  124.      * @var bool
  125.      * @access private
  126.      */
  127.     var $_good = true;
  128.  
  129.     // }}}
  130.     // {{{ setFoo()
  131.  
  132.     /**
  133.      * Registriert den Zustand des Foo-Universums
  134.      *
  135.      * Die Zusammenfassung für eine Methode sollte besser in der 3. Person
  136.      * Einzahl statt in der 2. Person formuliert werden.
  137.      * Das Verb sollte am Anfang stehen.
  138.      *
  139.      * Die Zusammenfassung sollte mehr Informationen liefern, die über den
  140.      * Methodennamen hinaus gehen. Die besten Methodennamen sind
  141.      * selbst beschreibend, sie sagen was die Methode im Grunde macht.
  142.      * Wenn die Zusammenfassung den Methodennamen nur in Form eines
  143.      * Satzes wiederholt, liefert sie keine zusätzlichen Informationen.
  144.      *
  145.      * Beispiele für die Zusammenfassung:
  146.      *   + Sets the label              (empfohlen)
  147.      *   + Set the label               (vermeiden)
  148.      *   + This method sets the label  (vermeiden)
  149.      *
  150.      * Als nächstes werden die üblichen Tags für Methoden angeführt.
  151.      * Ein @param-Tag muss für jeden Parameter angegeben werden.
  152.      * Die Tags @return und @access sind wahlfrei. Das @throw-Tag
  153.      * muss angegeben werden, wenn die Methode Exceptions wirft.
  154.      * Das Tag @static ist erforderlich, wenn die Methode statisch
  155.      * aufgerufen werden kann. Die übrigen Tags brauchen Sie nur
  156.      * angeben, wenn diese benötigt werden. Bitte geben Sie die
  157.      * Tags in der Reihenfolge an, wie sie hier aufgeführt sind.
  158.      * phpDocumentor bietet weitere Tags, benutze Sie diese, wenn
  159.      * es sinnvoll ist.
  160.      *
  161.      * Das @param-Tag umfasst den Datentypen, den Parameter-Namen, gefolgt
  162.      * von einer Beschreibung. Per Konvention sollte die Beschreibung beginnen
  163.      * mit dem Datentyp, dem ein Artikel ("a", "an" oder "the") vorangestellt
  164.      * werden kann. Setzen Sie zwei Leerzeichen zwischen dem Namen
  165.      * des Parameters und seiner Beschreibung für eine bessere Lesbarkeit.
  166.      *
  167.      * Wenn Sie einen Satz schreiben, starten Sie nicht mit einem
  168.      * Großbuchstaben und beenden Sie ihn nicht mit einem Punkt:
  169.      *   + the string to be tested
  170.      *
  171.      * Wenn Sie mehr als einen Satz schreiben, setzen Sie einen Punkt und
  172.      * beginnen Sie den zweiten Satz mit einem Großbuchstaben:
  173.      *   + the string to be tested. Must use UTF-8 encoding.
  174.      *
  175.      * Das @return-Tag sollte den Datentyp und eine Beschreibung des
  176.      * zurückgegebenen Wertes enthalten. Der Datentyp kann einer von PHP's
  177.      * Datentyp sein (int, float, bool, string, array, object, resource, mixed)
  178.      * und sollte den primär zurückgegebenen Wert enthalten. Z.B.
  179.      * eine Methode gibt korrekterweise ein Objekt zurück und nur im
  180.      * Fehlerfall 'false', dann sollten Sie 'object' angeben statt
  181.      * 'mixed'. Verwenden Sie 'void' wenn nicht zurückgegeben wird.
  182.      *
  183.      * Hier ein Beispiel für Quellcode-Texte:
  184.      * <code>
  185.      * require_once 'Net/Sample.php';
  186.      *
  187.      * $s = new Net_Sample();
  188.      * if (PEAR::isError($s)) {
  189.      *     echo $s->getMessage() . "\n";
  190.      * }
  191.      * </code>
  192.      *
  193.      * Hier ein Beispiel für Nicht-PHP-Code:
  194.      * <samp>
  195.      * pear install net_sample
  196.      * </samp>
  197.      *
  198.      * @param string $arg1  the string to quote
  199.      * @param int    $arg2  an integer of how many problems happened.
  200.      *                       Rücken Sie nachfolgende Zeilen in der Beschreibung
  201.      *                       entsprechend ein.
  202.      *
  203.      * @return int  the integer of the set mode used. FALSE if foo
  204.      *               foo could not be set.
  205.      * @throws exceptionclass  [description]
  206.      *
  207.      * @access public
  208.      * @static
  209.      * @see Net_Sample::$foo, Net_Other::someMethod()
  210.      * @since Method available since Release 1.2.0
  211.      * @deprecated Method deprecated in Release 2.0.0
  212.      */
  213.     function setFoo($arg1, $arg2 = 0)
  214.     {
  215.         /*
  216.          * Das ist ein "Block Kommentar". Das Format entspricht
  217.          * den obigen Kommentaren, mit der Ausnahme, das der Kommentarbeginn
  218.          * nur einen Stern enthält.
  219.          * phpDocumentor wertet diese nicht aus.
  220.          */
  221.         if ($arg1 == 'good' || $arg1 == 'fair') {
  222.             $this->foo = $arg1;
  223.             return 1;
  224.         } elseif ($arg1 == 'poor' && $arg2 > 1) {
  225.             $this->foo = 'poor';
  226.             return 2;
  227.         } else {
  228.             return false;
  229.         }
  230.     }
  231.  
  232.     // }}}
  233. }
  234.  
  235. // }}}
  236.  
  237. /*
  238. * Local variables:
  239. * tab-width: 4
  240. * c-basic-offset: 4
  241. * c-hanging-comment-ender-p: nil
  242. * End:
  243. */
  244.  
  245. ?>

(Quelle: PEAR Coding Standard, 05.02.2008)

Letzte Änderung am 22.08.2008 22:12 Uhr von chueser. navigation & toc