Programmierstandards

PHP

Strukturell und inhaltlich angelehnt an den Zend Framework PHP Code Standard, hier werden nur von diesem abweichende Punkte genannt.

PHP Dateiformatierung

Allgemein

  • Schließender PHP-Tag (“?>“) ist optional
  • Dateien werden in UTF-8 gespeichert
  • Jeder neuen Datei muss vor dem ersten Commit die SVN-Property svn:keywords mit dem Wert „Id“ zugewiesen werden, damit die $Id$-Tags korrekt umgesetzt werden (für das automatische Hinzufügen von SNV-Properties siehe die SVN-Dokumentation

Einrückung

  • Einrückung mit 2 Leerzeichen (keine Tabs!)

Namenskonventionen

Klassen

  • Klassen unterhalb des /lib/Dsao-Ordners beginnen mit 'Dsao_' gefolgt von der Ordnerstruktur bis zur Datei, jeweils durch Unterstriche getrennt (Beispiel: Name ist 'SomeClass' und sie liegt in /lib/Dsao/Controller/SomeClass.php, dann ergibt sich als Klassenname 'Dsao_Controller_SomeClass')
  • Kontrollerklasse, die unterhalb des /application-Ordners liegen beginnen jeweils mit der Funktion, die sie erfüllen bzw. der Bereich für den sie eingesetzt werden, enden auf 'Controller' und befinden sich in den gleichnamigen PHP-Dateien (Beispiel: IndexController, RegisterController; /application/default/controller/IndexController.php, /application/user/controller/RegisterController.php)
  • Tabellenklassen kommen in den ordner /lib/Dsao/Table/TableName.php (Klassenname wäre entsprechend 'Dsao_Table_TableName')
  • Die Modellklassen befinden sich unterhalb des /lib/Dsao/Model-Ordners, soweit nötig erhält jeder Kontroller seine eigene Modellklasse
  • Objektorientierte Mechanismen zur Bündelung von Daten und Methoden (z.B. eine Klasse 'User', um einen Benutzer und die damit verbundenen Methoden darzustellen) gehören nicht in die Modelklasse, sondern in eigene Klassen im /lib/Dsao-Ordner

Code-Stil

Kontrollstrukturen

  • Geschweifte Klammern _immer_ in eigene Zeile
  • Geschweifte Klammern auch dann setzen, wenn sie optional sind

Inline Dokumentation

Für die Inline-Dokumentation gibt es einen eigenen Artikel.

E_STRICT-kompatibler Code

  • Sämtlicher Code ist auf E_STRICT-Kompatibilität zu überprüfen

Sprachdateien

  • Für Sprachdateien werden Arrays verwendet
  • Um einen zu übersetzenden String hinzuzufügen muss folgendes geschrieben werden:
$var = Zend_Registry::get('translate')->_('translation_string');
  • In den meisten Klassen, in denen Textausgabe benötigt wird, ist jedoch eine Klassenvariable verfügbar, die den Aufruf über Zend_Registry überflüssig macht
  • Übersetzungen müssen nicht sofort bereitgestellt werden
  • Die Konstanten, welche die Sprachzeichenketten repräsentieren, bestehen aus Kleinbuchstaben, wobei jedes Wort durch einen Unterstrich getrennt wird (Beispiel: „some_string“), des weiteren sind die Konstanten englisch zu benennen
  • Die Sprachzeichenketten sollten folgendermaßen aufgebaut sein: 'module_controller_action_category_description', also z.B. 'forum_thread_show_error_invalid_id' oder 'user_register_username_affirmation_email_sent'
  • Es gibt eine globale Sprachdatei /language/global.php, in der alle modulunabhängigen Sprachzeichenketten gespeichert werden
  • Jedes Modul hat seine eigene Sprachdatei, /language/module.php

Aufbau einer Sprachdatei

  • Auch Sprachdateien haben einen o.g. Dateiheader (und SVN-Property 'Id') zu erhalten
  • Sprachdateien sind allgemein folgendermaßen aufgebaut
/**
 * Sprachdatei für das 'xyz'-Modul
 *
 * LICENSE:  This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @copyright  2008 DSAo-Md
 * @license    http://www.gnu.org/licenses/gpl-3.0.html GNU Public License
 * @version    SVN: $Id$
 */
 
$languages = array
(
  /**
   * module_controller_action
   * @see controllerController::actionAction() (falls vorhanden)
   */
  // Kommentar zur Konstanten 'message1'
  'module_controller_action_section_message1_long' => "Nachricht1",
 
  // Kommentar zur Konstanten 'message2'
  'module_controller_action_section_message2'      => "Nachricht2",
 
 
  /**
   * module_controller_action2
   * @see controllerController::action2Action() (falls vorhanden)
   */
  // Kommentar zur Konstanten 'message3'
  'module_controller_action2_section_message3' =>
    "Eine etwas längere Nachricht,\ndie sogar Zeilenumbrüche enthält.\n".
    "Eine solche Nachricht sollte nach max. 80 Zeichen umgebrochen, ".
    "und in der nächsten Zeile weitergeführt werden.",
);
 
return $languages;
  • Zwischen Sektionen sind zwei Leerzeilen einzufügen, zwischen einzelnen Sprachzeichenketten eine Leerzeile; vor jede Sektion ist außerdem wie oben gezeigt ein Kommentar zu setzen
  • Bei Sprachzeichenketten gleicher Sektion ist der Zuweisungspfeil auf gleicher Höhe zu positionieren
  • Um die Ordnung aufrecht zu erhalten, ist unbedingt auf eine alphabetische Sortierung zu achten; wie gezeigt sind Kommentare erwünscht

SQL

  • Es sollte für spezielle Fälle mit komplexeren Datenbankoperationen die ZF-Dokumentation hinzugezogen werden, um die effektivste Art der Verarbeitung zu finden

Achtung: Von der herkömmlichen Syntax bei fetchRow() und fetchAll() wird abgeraten, man kann stattdessen ein Objekt der Zend_Db_Select-Klasse übergeben. Für Details siehe ZF-Dokumentation.

Benennung und Standardwerte

  • Bei der Benennung werden englische Begriffe verwendet, dabei wird, wie bei Variablen, die camelCase Schreibweise benutzt
  • Es sollte jeder Spalte ein aussagekräftiger Kommentar hinzugefügt werden
  • Es sollten alle Feldern, abgesehen von den wirklich essentiellen, ein Standardwert (ggf. auch NULL) erhalten

Anordnung der Tabellenfelder

  • Das erste Feld stellt (falls vorhanden) den Primärschlüssel (oder eine mit einer anderen Tabelle verbundene ID o.ä.) dar, darauf folgen, alphabetisch sortiert, alle weiteren IDs (es wird ihnen immer ein 'id_' vorangestellt) und anschließend alle weiteren Felder, wiederum alphabetisch sortiert (zur Gruppierung sollte jeweils ein Präfix verwendet werden)

Änderungen an Tabellenstruktur

Wenn einer der Dateien unterhalb von /sql/ geändert wird, so sollte entweder eine Diff-Dateie oder eine Patch-Datei erstellt werden, damit Benutzer ohne Datenverluste die Datenbank aktualisieren können.

Für das Erstellen der Patch-Dateien kann z.B. das Programm MySQL table patcher verwendet werden.

SELECT

  • Zum Auslesen einzelner Datensätze wird folgendes Konstrukt bevorzugt:
$row = $table->select()->where('some_col = ?', 1)->fetchRow();
 
echo $row->some_col;
  • Zum Auslesen einzelner Datensätze anhand des Primärschlüssels wird folgendes Konstrukt bevorzugt:
$row = $table->find($value)->current();
 
echo $row->some_col;
  • Zum Auslesen aller Spalten mehrerer Datensätze wird folgendes Konstrukt bevorzugt:
$rowset = $table->select()->where('some_col = ?', 1)->fetchAll();
 
foreach ($rowset as $row)
{
  echo $row->some_col;
}
  • Zum Auslesen mehrerer Datensätze anhand der Primärschlüssel wird folgendes Konstrukt bevorzugt:
$values = array (1,4,8); // z.B. Benutzer mit den IDs 1,4 und 8 auslesen
$rowset = $table->find($values);

INSERT

  • Zum Einfügen eines Datensatzes wird folgendes Konstrukt bevorzugt:
$data = array(
    'col1' => 'val1',
    'col2' => 'val2',
    'col3' => 'val3'
);
 
$table->insert($data);

UPDATE

  • Zum Ändern eines Datensatzes wird folgendes Konstrukt bevorzugt:
$data = array
  (
    'someCol' => 2
  );
 
$sqlWhere = $this->_getModel()->getAdapter()->quoteInto('id = ?', $id);
 
// oder als Array
$sqlWhere = array(
    $this->_getModel()->getAdapter()->quoteInto('id = ?', $id),
    $this->_getModel()->getAdapter()->quoteInto('otherCol = ?', $otherCol),
);
 
$table->update($data, $sqlWhere);
 
// Soll eine bereits geladene Zeile geändert werden, ist dies einfacher:
$row->col = 5;
$row->save();

DELETE

* Zum Löschen eines Datensatzes wird folgendes Konstrukt bevorzugt:

 
$sqlWhere = $this->_getModel()->getAdapter()->quoteInto('id = ?', $id);
 
// oder als Array (s.o.)
 
$table->delete($sqlWhere);
 
// oder, sofern Zeile geladen wurde
$row->delete();

Best practices

  • Jeder SVN-Commit wird mit einem aussagekräftigen Kommentar (und ggf. einem Hinweis auf das bearbeitete Ticket) versehen

XHTML

Es wird XHTML 1.0 strict verwendet.

  • Für Einrückung und Zeilenläge gelten die Konventionen aus der PHP-Sektion
  • Tags sollten immer in einer eigenen Zeile stehen
    • Bei kurzen Tags mit Textinhalt ist es dem Programmierer überlassen, ob er sowohl öffnenden und schließenden Tag als auch den Text in eine Zeile schreibt oder nicht (es sollte hierbei darauf geachtet werden, die Zeilenlänge von 80 Zeichen einzuhalten)
  • Hat ein Tag mehrere Eigenschaften, so sollten diese in eigene Zeilen geschrieben werden, sofern die Zeilenlänge von 80 Zeichen überschritten
  • HTML-Kommentare sollten insgesamt vermieden werden (stattdessen Smarty-Kommentare!), nur im Devel-Template sind Kommentare am Anfang und Ende von Templates / Codeabschnitten folgendermaßen zu setzen
<!-- begin: module/controller/template.tpl -->

bzw.

<!-- end: module/controller/template.tpl -->

CSS

Es werden CSS 2 (deutsch) verwendet.

  • Eigenschaften von Tags sind wenn möglich in die CSS auszulagern
  • Klassen und IDs sollten nach den o.g. Namenskonventionen benannt werden und eindeutige Namen, denen das Präfix des Moduls vorangestellt wird, erhalten
  • Kommentare vor den Klassen / IDs ist erwünscht (vor allem, wenn aus dem Namen die Verwendung nicht klar hervorgeht)
  • Alphabetische Sortierung (erst IDs, dann Klassen), ggf. auch primär nach Kontext sortiert, wird erwartet
  • Als Validator kann der W3C-Validator verwendet werden
  • Als Referenz kann ich die CSS 2 Reference empfehlen

JavaScript

JavaScript (und auch Ajax) können benutzt werden, darf aber immer nur so eingesetzt werden, dass auch Benutzer, die JavaScript deaktiviert haben, das System noch ordnungsgemäß nutzen können.

  • Es gelten gleiche Konventionen wie für PHP (in den für JavaScript zutreffenden Bereichen)
  • Als Referenz kann ich die JavaScript Seite der w3schools empfehlen

Funktionen

Event-Handler

  • Alle Funktionen, die als Parameter ein Prototype-Event übernehmen, sollten mit 'Handler' benannt werden, also bspw. 'someHandler()'

Response-Handler

  • Alle Funktionen, die eine Ajax-Antwort als Prameter übernehmen, sollten mit 'Responder' (eigentlich müsste es korrekt 'ResponseHandler' heißen, dies würde allerdings in sehr langen Funktionsnamen resultieren) benannt werden, also bspw. 'someResponder()'

Smarty

Als Template Engine wird Smarty verwendet.

  • Einrückungen sollten vermieden werden, um die HTML-Ausgabe nicht unlesbar zu machen (zumindest nachher schauen, wie die HTML-Ausgabe aussieht)
  • Kommentare sind erwünscht; wenn das Template Parameter erwartet, sollten diese am Anfang kurz dokumentiert werden (der Einheitlichkeit halber mit phpDoc-Tags)
  • An den Anfang jedes Templates ist der gleiche Datei-Header zu stellen, wie in der PHP Sektion beschrieben

Codedokumentation

Im Namensbereich Code befinden sich alle Code-Dokumentationen. Wer eine wichtige oder komplizierte Komponente implementiert, oder einen guten Weg gefunden hat, ein bestimmtes, häufig auftretendes Problem zu lösen, der kann eine Seite innerhalb dieser Hierarchie erstellen, um neuen Programmierern den Einstieg zu erleichtern.

 
code/konventionen/programmierung.txt · Zuletzt geändert: 01.06.2009 18:43 von saviola
 
Recent changes RSS feed Valid XHTML 1.0 Valid CSS Driven by DokuWiki