Coding Guidelines

Werbung
intermatix
Coding Guidelines
Autor:
Bernd Alter ([email protected])
Stand:
12.10.2011
Übersicht
Umfang
Dieses Dokument stellt die Coding-Standards und Programmierrichtlinien für PHP-Entwickler-Teams bereit. Die Hauptthemen sind:
Allgemeine Grundsätze
Dateiformatierung
Namenskonventionen
Programmierstil
Inline-Dokumentation
Musterklasse
Vorteile
Gute Programmierstandards sind wichtig für jedes Software-Projekt, insbesondere wenn mehrere Entwickler zusammen an einem Projekt arbeiten. Coding-Standards verhelfen zu einem
qualitativ hohen und einheitlichen Code mit weniger Fehlern und einfacher Wartung.
Allgemeine Grundsätze
Jede Funktion oder Methode erfüllt nur einen Zweck, den aber möglichst gut.
Alles ist objektorientiert.
Alles wird in Englisch verfasst.
Alles ist für den phpDocumentor dokumentiert.
Alles ist so kurz wie möglich gehalten.
Alles ist so zeitlos wie möglich.
Dateiformatierung
Einzug
Benutze einen Einzug von zwei Leerzeichen ohne Tabulatoren. Die Konfiguration des
verwendeten Editors/IDE sollte (sofern möglich) so eingestellt werden, dass Tabulatoren
als Leerzeichen ausgegeben werden, um Tabulatorzeichen im Quellcode zu vermeiden.
Leerzeichen
Es muss immer ein Leerzeichen eingefügt werden nach Variablen, Operatoren sowie nach folgenden Zeichen: ( ) , ;
Eine Ausnahme sind runde Klammern bei Typumwandlungen.
Vor bzw. nach eckigen Klammern ([]) sollen keine Leerzeichen eingefügt werden.
Beispiele
falsch
richtig
for($i=0;$i<=100;$i++)
{
$array[$i]=($i+5)*10;
echo sprintf('Nr %02d',$i);
$toggle=(bool)($i%2);
}
for ( $i = 0; $i <= 100; $i++ )
{
$array[$i] = ( $i + 5 ) * 10;
echo sprintf( 'Nr %02d', $i );
$toggle = (bool) ( $i % 2 );
}
Maximale Zeilenlänge
Die optimale Zeilenlänge ist 80 Zeichen; d.h. Entwickler sollten so nah wie möglich an der 80
Zeichen Grenze bleiben, soweit dies praktikabel ist. Längere Zeilen sind aber erlaubt. Die maximale Länge einer Zeile mit PHP-Code beträgt 120 Zeichen.
Zeilenabschluss
Zeilen müssen mit einem Zeilenvorschub (LF) enden. Die Konfiguration des verwendeten
Editors/IDE sollte (sofern möglich) so eingestellt werden, dass Leerzeichen am Ende einer
Zeile automatisch entfernt werden.
Namenskonventionen
Für Bezeichner (Klassennamen, Methoden, Methodenparameter, Variablen, Konstanten etc.)
werden ausschließlich englische Ausdrücke verwendet.
Als Schreibweise gilt die (lower)CamelCase-Konvention.
class SampleClass
{
private $url;
public $destinationUrl;
public function getUrl()
{
...
}
}
Bezeichner sind immer sprechend zu benennen und sollten nicht abgekürzt werden.
Beispiele
falsch
richtig
function getUserByNN()
function getUserByNickname()
$pa
$pollAnswers
Klassen
Klassennamen dürfen nur alphanumerische Zeichen enthalten. Zahlen sind erlaubt, jedoch zu
vermeiden.
Wenn ein Klassenname aus mehreren Wörtern besteht, wird der erste Buchstabe von jedem
neuen Wort gross geschrieben. Aufeinanderfolgende Grossbuchstaben sind nicht erlaubt; z.B.
die Klasse "MYSQLHelper" ist nicht erlaubt, "MySqlHelper" aber schon.
Schnittstellen
Schnittstellenklassen müssen denselben Namenskonventionen der normale Klassen folgen (siehe oben), müssen jedoch mit dem Schlüsselwort "Interface" enden.
Dateinamen
Für alle anderen Dateien dürfen nur alphanumerische Zeichen, Underscores und Trennstriche
("-") verwendet werden. Leerzeichen sind nicht erlaubt. Jede Datei, die PHP-Code enthält muss
die Endung ".php" haben.
Funktionen und Methoden
Funktionsnamen dürfen nur alphanumerische Zeichen enthalten. Zahlen sind erlaubt, jedoch
zu vermeiden. Underscores sind nicht erlaubt. Funktionsnamen müssen immer mit einem
Kleinbuchstaben beginnen.
Wenn eine Funktion aus mehreren Namen besteht, muss der Anfangsbuchstabe von jedem
neuen Wort grossgeschrieben werden. Diese Benennungsmethode wird auch studlyCaps oder
camelCaps genannt. Funktionen und Methoden müssen so klar wie möglich bezeichnet werden,
damit anhand des Funktionsnamen jeder versteht, was die Funktion macht.
Beispiele:
filterInput()
getElementById()
addAttachment()
In der objektorientierten Programmierung sollten alle Klassenvariablen mit den Suffixen get
oder set in den Methoden verwendet werden.
Wenn Design Patterns, wie Singleton oder Factory Patterns, verwendet werden, sollte der Methodenname den Pattern-Name enthalten, damit das Pattern beim Lesen verständlich ist.
Zusammenhangslose Funktionen (floating functions) sind in einer abstrakten Klasse unterzubringen und als statisch zu bezeichnen.
Variablen
Variablennamen dürfen nur aus alphanumerischen Zeichen bestehen. Underscores sind nicht
erlaubt. Zahlen sind erlaubt, jedoch zu vermeiden.
Wie bei den Funktionsnamen müssen alle Variablen mit Kleinbuchstaben beginnen und der "camelCaps" Namenskonvention folgen.
Variablennamen sind so kurz und so verständlich wie möglich zu halten. Variablen wie $i und
$n sollten nur bei kleineren Schleifen verwendet werden. Wenn eine Schleife mehr als 20 Zeilen hat, muss der Zähler ($i oder $n) genauer bezeichnet werden, z.B. $fooBarCounter.
Konstanten
Konstantennamen dürfen nur aus alphanumerischen Zeichen und Underscores bestehen. Zahlen sind erlaubt in, jedoch zu vermeiden. Konstanten müssen immer in Grossbuchstaben geschrieben werden.
Um die Lesbarkeit zu erleichtern, werden die einzelnen Wörter mit Underscores getrennt. Zum
Beispiel EMBED_SUPPRESS_EMBED_EXCEPTION ist erlaubt, nicht erlaubt ist
EMBED_SUPPRESSEMBEDEXCEPTION.
Klassenkonstanten müssen als const definiert werden. Allgemeine Konstanten, die mit define
definiert werden, sind nur in Ausnahmefällen erlaubt.
Programmierstil
Lesbarkeit
Um einen gut lesbaren Quellcode zu erhalten, sollten folgende Richtlinien befolgt werden:
der Quellcode sollte aufgeräumt und gut strukturiert sein
an Leerzeichen muss nicht gespart werden
vor und hinter Blöcken (Bedingungen und Schleifen) sollte eine Leerzeile stehen
PHP Code Abgrenzung
PHP Code muss immer mit den folgenden Tags abgegrenzt werden:
<?php
...
?>
In reinen PHP-Dateien (Klassen, Bibliotheken, etc.) muss nur der öffnende PHP-Tag am
Anfang der Datei stehen, der schließende Tag sollte weggelassen werden, da evtl. Leerzeichen nach dem schließenden Tag eine ungewollte Ausgabe und damit Fehler erzeugen können
('header already sent').
Strings
Ein String sollte grundsätzlich mit einfachen Apostrophen (single quotes) abgegrenzt werden. Dies hat den Vorteil, dass PHP Code im String nicht ausgeführt wird und so z.B. HTML
Ausgaben einfacher sind.
Nur Datenbankabfragen werden zwischen doppelte Apostrophen (double quotes) gestellt.
HINWEIS: Alle SQL-Befehle werden immer gross geschrieben.
WICHTIG: Bei String-Konkatenation wird statt des Punktoperators oder direkter Einbettung
von Variablen in Strings die Funktion sprintf() verwendet.
falsch
$sql = "SELECT * FROM ".$table." WHERE id='".$id."'";
$amount = 10;
$formatted = "EUR $amount,00";
richtig
$sql = sprintf( "SELECT * FROM %s WHERE id='%d'", $table, $id );
$amount = 10;
$formatted = sprintf( 'EUR %0.2f', $amount );
Vorteile:
höhere Typsicherheit
Minimierung von Fehlerquellen
bessere Lesbarkeit des Quellcodes
integrierte Formatierungsmöglichkeiten
Arrays mit numerischem Index
Negative Zahlen sind nicht erlaubt als Array-Index. Arrays dürfen mit positiven Zahlen als Index beginnen, jedoch ist empfohlenswert jeden Array mit 0 zu beginnen. Wenn die Indizes eines Arrays definiert werden, muss nach jedem Komma ein Leerzeichen stehen:
$sampleArray = array( 1, 2, 3, 'Buxa', 'Buxa' );
Es ist auch erlaubt, einen Array über mehrere Zeilen aufzuteilen. In diesem Fall muss jede
neue Zeile unter dem 1. Element der 1. Zeile beginnen.
Beispiel:
$sampleArray = array(
1, 2, 3, 'Buxa', 'Buxa',
$a, $b, $c,
56.44, $d, 500
);
Assoziative Arrays
Bei der Definition von assoziativen Arrays, ist ein Element pro Zeile anzugeben. Dabei ist zu
beachten, dass der "=>" bei allen Zeilen am gleichen Ort steht und somit Schlüssel und Wert
untereinander stehen. Die Abstände werden mit Leerzeichen ausgeglichen:
$sampleArray = array(
'firstKey' => 'firstValue',
'secondKey' => 'secondValue',
'thirdKey' => 'thirdValue'
);
Die folgende Schreibweise ist auch erlaubt:
$sampleArray['firstKey'] = 'firstValue';
$sampleArray['secondKey'] = 'secondValue';
$sampleArray['thirdKey'] = 'thirdValue';
WICHTIG: Array-Schlüssel und -Wert müssen immer in Apostrophen (single quotes) gesetzt
werden!
Klassendeklarationen
Klassen müssen die folgenden Namenskonventionen einhalten:
Die geschweifte Klammer wird immer unterhalb des Klassennamens geschrieben ("one true
brace" form).
Jede Klasse muss einen Dokumentations-Block im phpDocumentor-Standard enthalten.
Jeder Code innerhalb der Klasse muss zwei Leerzeichen eingerückt sein.
Es darf nur eine Klasse pro Datei definiert werden.
Zusätzlicher Code in einer Klassendatei ist zu vermeiden. In diesem Fall müssen 2 leere Zeilen
Abstand zwischen Klasse und zusätzlichem Code gemacht werden.
Beispiel einer gültigen Klassendeklaration:
/**
* Class Docblock Here
*/
class MyClass
{
// Entire content of class must be indented two spaces
}
Klassenvariablen
Klassenvariablen müssen die folgenden Namenskonventionen einhalten:
Alle in einer Klasse verwendeten Klassenvariablen müssen innerhalb der Klasse zuoberst aufgelistet werden. Erst darunter folgen die Klassenmethoden.
Das var-Konstrukt ist nicht erlaubt. Klassenvariablen sind immer nach Sichtbarkeit zuzuordnen, d.h. mit den private, protected oder public Konstrukten. Klassenvariablen dürfen als
public definiert werden, dieses ist jedoch zu vermeiden. Verwenden Sie die Zugriffsmethoden
mit set und get als Präfix.
Eine Klassenvariablen sollte - sofern sie nicht public ist - immer zuerst als private deklariert
werden, erst wenn die klare Notwendigkeit besteht, z.B. wegen der Vererbung, sollte sie als
protected deklariert werden.
/**
* Class Docblock Here
*/
class MyClass
{
/**
* Variable Docblock Here
*/
private $privateVar = null;
/**
* Variable Docblock Here
*/
protected $protectedVar = null;
/**
* Variable Docblock Here
*/
public $publicVar = null;
}
Funktionen- und Methoden-Deklaration
Funktionen und Klassenmethoden müssen die folgenden Namenskonventionen einhalten:
Methoden müssen immer zuerst mit ihrer Sichtbarkeit deklariert werden, d.h. mit den private, protected oder public Konstrukten. Wie bei Klassen wird die öffnende geschwungene
Klammer unterhalb des Methodennamens definiert ("one true brace" form). Zwischen Funktions- oder Methodenname und der Klammer für deren Argumente / Parameter darf kein Leerzeichen sein.
Eine Klassenmethodesollte - sofern sie nicht public ist - immer zuerst als private deklariert
werden, erst wenn die klare Notwendigkeit besteht, z.B. wegen der Vererbung, sollte sie als
protected deklariert werden.
Hier ein Beispiel einer gültigen Methodendeklaration in einer Klasse:
/**
* Class Docblock Here
*/
class Foo
{
/**
* Method Docblock Here
*/
public function sampleMethod( $a )
{
// Entire content of function must be indented two spaces
}
/**
* Method Docblock Here
*/
protected function _anotherMethod()
{
// ...
}
/**
* Method Docblock Here
*/
private function _anotherNewMethod(Array $b)
{
// ...
}
}
HINWEIS: Die Übergabe von Parametern, die ein Objekt referenzieren, ist nur durch die Definition der Referenzierung in der Funktions- oder Methodendeklaration beim Parameter selbst
erlaubt:
function sampleMethod(&$a)
{
// ...
}
Bei Funktionen mit Objekten oder Arrays als Parameter werden diese mit Typehinting deklariert:
class Foo
{
function objectMethod( Bar $sampleObject )
{
// ...
}
function arrayMethod( Array $sampleArray )
{
// ...
}
}
Call-time pass by-reference ist nicht erlaubt.
Der Rückgabewert einer Funktion oder Methode darf nicht in Klammern gesetzt werden. Dies
verschlechtert die Lesbarkeit und kann zudem zu Fehlern führen, wenn eine Funktion oder Methode später eine Referenz zurückgibt.
function foo()
{
return($this->bar); // falsch
return $this->bar; // richtig
}
Anwendung von Funktionen und Methoden
Funktionsparameter werden immer mit einem Leerzeichen nach dem Komma aufgerufen. Hier
ein gültiges Beispiel eines Aufrufs einer Funktion mit drei Parametern:
threeArguments(1, 2, 3);
Call-time pass by-reference ist nicht erlaubt. Für Funktionen, die Arrays als Parameter erlauben, kann der Array wie folgt auf mehrere Zeilen verteilt werden, damit die Lesbarkeit erhöht
wird.
threeArguments(array(1, 2, 3), 2, 3);
threeArguments(array(1, 2, 3, 'Buxa', 'Projects',
$a, $b, $c,
56.44, $d, 500), 2, 3);
Kontrollstrukturen
Klammern
Blöcke von Kontrollstrukturen (Bedingungen, Schleifen) werden immer in geschweifte Klammern gesetzt, auch wenn der auszuführende Code nur eine Zeile umfasst. Sowohl die öffnende
als auch die schließende Klammer stehen in einer separaten Zeile.
Beispiele
falsch
richtig
if ( $i == 1 )
echo $someVariable;
if ( $i == 1 )
{
echo $someVariable;
}
for ( $i = 0; $i < 10; $i++ )
echo pow( $i, 2 );
for ( $i = 0; $i < 10; $i++ )
{
echo pow( $i, 2 );
}
if / else / else if
Basis-Kontrollstukturen mit dem if, else und else if Konstrukt müssen vor und nach den
Klammern mit der Bedingung je ein Leerzeichen haben. Auch die Operatoren müssen mit Leerzeichen am Anfang und am Ende leserlich gemacht werden.
Um Blöcke zu gruppieren, müssen Klammern eingesetzt werden.
Bei längeren Bedingungen werden alle Bedingungen untereinander dargestellt, um die Lesbarkeit zu erhöhen. Die öffnende geschweifte Klammer wird unterhalb der Bedingung geschrieben.
Die abschliessende geschweifte Klammer erhält immer eine separate Zeile. Jeder Code innerhalb der geschweiften Klammern muss zwei Leerzeichen eingerückt werden.
if ( $a != 2 )
{
$a = 2;
}
if-Bedingungen, die else if oder else enthalten, müssen folgendermassen formatiert werden:
if ( $a != 2 )
{
$a = 2;
}
else
{
$a = 7;
}
if (
{
$a
}
else
{
$a
}
else
{
$a
}
$a != 2 )
= 2;
if ( $a == 3 )
= 4;
= 7;
HINWEIS: Das zusammen geschriebene elseif Konstrukt ist nicht erlaubt!
HINWEIS: Der dreifach konditionale Operator (<condition>?<true>:<false>) sollte nach
Möglichkeit nicht verwendet werden..
switch
Kontrollstrukturen mit dem switch-Konstrukt muss wie if, else und else if vor und nach
den Klammern des Switch-Elements ein Leerzeichen enthalten. Code innerhalb der Switchanweisung muss zwei Leerzeichen eingerückt werden. Unter dem "case" Element müssen bis zum
nächsten case-Element jeder Code zwei Leerzeichen eingerückt werden.
switch ($sampleNumber)
{
case 1:
// ...
break;
case 2:
// ...
break;
default:
// ...
break;
}
Das default-Konstrukt sollte bei einer switch-Bedingung nie weggelassen werden.
HINWEIS: Manchmal kann es nötig sein, ein case-Element zu schreiben, auf das kein break
oder return folgt. In diesem Falle muss folgender Kommentar anstelle des break eingefügt
werden:
switch ( $value )
{
case 'xyz':
// break intentionally omitted
case 'abc':
echo $value;
break;
default:
break;
}
while / for / foreach
Die Schleifen while, for und foreach werden gleich wie if, else und else if formatiert.
for ( $i = 0; $i < 10; $i++ )
{
echo sprintf( "Hello %d\n ", $i );
}
foreach ( $sampleArray as $key => $value )
{
echo sprintf( "%s is %s\n ", $key, $value );
}
while ( $row = mysql_fetch_assoc( $result ) )
{
echo sprintf( "%s\n ", $row['id'] );
}
Inline-Dokumentation
Formatierung
Alle Dokumentationsblöcke (docblocks) müssen mit den Konventionen von phpDocumentor
übereinstimmen. Mehr Infos dazu unter http://phpdoc.org.
Jede Quellcode-Datei für ein Framework muss zuoberst einen "file-level" docblock enthalten.
Darauf folgt ein "class-level" docblock oberhalb der Klassendeklaration. Die Raute ("#") darf
nicht als Kommentarvariante verwendet werden.
Dateien
Jede PHP-Datei muss im Minimum einen docblock mit den folgenden phpDocumentor Tags enthalten:
/**
* Short description for file
*
* Long description for file (if any)...
*
* LICENSE: Some license information
*
* @copyright 2007 intermatix
* @license http://www.intermatix.de/license.txt intermatix Licence 1.0
* @version $Id$
* @link
http://dev.intermatix.de/package/PackageName
* @since
File available since Release 1.0
*/
Klassen
Jede Klasse muss im Minimum einen docblock mit den folgenden phpDocumentor Tags zuoberst enthalten:
/**
* Short description for class
*
* Long description for class (if any)...
*
* @copyright 2007 intermatix
* @license http://www.intermatix.de/license.txt
intermatix Licence 1.0
* @version Release: @package_version@
* @link
http://dev.intermatix.de/package/PackageName
* @since
Class available since Release 1.0
*/
Funktionen
Jede Funktion oder Klassenmethoden muss im Minimum einen docblock mit den folgenden
Tags enthalten: Beschreibung, Parameter, Rückgabewerte. Der "@access" Tag ist nicht nötig,
weil dieser schon anhand des "public", "private", oder "protected" Konstrukts ermittelt werden
kann. Dies gilt auch für den "@abstract" Tag.
/**
* Short description for the function
*
* Long description for the function (if any)...
*
* @param array $array Description of array
* @param string $string Description of string
* @return boolean
*/
Wenn eine Funktion oder Methode eine Exception ausgibt, ist der "@throws" Tag erforderlich:
@throws Exception_Class_Name Description
Variablen
Jede Klassenvariable muss im Minimum einen docblock mit einer Beschreibung und einem Typentag enthalten:
/**
* Description for the variable
* @var array
*/
Musterklasse
<?php
/**
* Imx_Lifeform_Human
*
* Creation and manipulation of human beeings.
*
* LICENSE: Free
*
* @copyright 2007 intermatix
* @license Free
* @version 1.0
* @package Imx_Lifeform
* @subpackage Human
* @link
http://dev.intermatix.de/Imx/Lifeform/Human
* @since
File available since Release 1.0
*/
// Imx_Lifeform
require_once 'Imx/Lifeform.php';
/**
* Creation and manipulation of human beeings.
*
* This fascinating class provides you to create and manipulate human beeings.
* This class also inherits properties and methods for age, size or weight from
* the parent class Imx_Lifeform. Most additional properties are declared as
* protected, because there could be some subclasses. Note that this is just
* a sample class and is not created for real usage.
*
* @copyright 2007 intermatix
* @license Free
* @version Release: 1.0
* @link
http://dev.intermatix.de/Imx/Lifeform/Human
* @since
Class available since Release 1.0
*/
class Imx_Lifeform_Human extends Imx_Lifeform
{
/**
* Valid colors for the eyes
* @var array
*/
static private $validEyeColors = array(
'blue',
'brown',
'gray',
'green'
);
/**
* Valid colors for the hair
* @var array
*/
static private $validHairColors = array(
'black', 'blond', 'brown',
'gray', 'red', 'white'
);
/**
* Valid colors for the skin
* @var array
*/
static private $validSkinColors = array(
'black', 'brown', 'red',
'white', 'yellow'
);
/**
* Color of the eyes
* @var string
*/
protected $eyeColor = null;
/**
* Color of the hair
* @var string
*/
protected $hairColor = null;
/**
* Color of the skin
* @var string
*/
protected $skinColor = null;
/**
* Constructor
*
* @return void
*/
public function __construct()
{}
/**
* Sets the color of the eyes.
*
* @param string $eyeColor Color of the eyes
* @return boolean
*/
public function setEyeColor( $eyeColor )
{
if ( in_array( strtolower( $eyeColor ), self::$validEyeColors ) )
{
$this->_eyeColor = strtolower( $eyeColor );
return true;
}
else
{
return false;
}
}
/**
* Sets the color of the hair.
*
* @param string $hairColor Color of the hair
* @return boolean
*/
public function setHairColor( $hairColor )
{
if ( in_array( strtolower( $hairColor ), self::$validHairColors ) )
{
$this->_hairColor = strtolower( $hairColor );
return true;
}
else
{
return false;
}
}
/**
* Sets the color of the skin.
*
* @param string $skinColor Color of the skin
* @return boolean
*/
public function setSkinColor($skinColor)
{
if ( in_array( strtolower( $skinColor ), self::$validSkinColors ) )
{
$this->_skinColor = strtolower( $skinColor );
return true;
}
else {
return false;
}
}
/**
* Returns the color of the eyes.
*
* @return string
*/
public function getEyeColor()
{
return $this->_eyeColor;
}
/**
* Returns the color of the hair.
*
* @return string
*/
public function getHairColor()
{
return $this->_hairColor;
}
/**
* Returns the color of the skin.
*
* @return string
*/
public function getSkinColor()
{
return $this->_skinColor;
}
}
Herunterladen