PHP/Fehler vermeiden

Aus Mikiwiki
< PHP
Version vom 19. Januar 2009, 18:09 Uhr von Michi (Diskussion | Beiträge) (→‎Abfrage von Zuständen)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Mit einer Reihe von Massnahmen kann die Qualität der eigenen Skripte erhöht werden:

  • Einhaltung von Code-Konventionen
  • Formatierung und Strukturierung
  • Abfrage von Zuständen

Einhaltung von Code-Konventionen

Code-Konventionen sind (aus Sicht des PHP-Parsers) unverbindliche Vorschriften oder Empfehlungen zur Schreibweise von Variablen und Funktionen. Grundsätzlich müssen die Namen nur den Anforderungen der Semantik genügen. Für die Lesbarkeit und Fehlersuche sind aber erweiterte Benennungsregeln empfehlenswert. Die Konventionen umfassen folgende Bereiche:

  • Namenskonventionen für Variablen, Objekte und Prozeduren
  • Kommentarkonventionen
  • Textformatierung und Einrückungen

Einheitlichkeit ist oberstes Gebot! Man sollte sich für englische oder deutsche Bezeichnungen entscheiden und dabei bleiben.

Konstanten können einfach durch Grossschreibung kenntlich gemacht werden. Bestehen die Namen aus mehreren Wörtern, werden die Wörter mit dem Unterstrich "_" getrennt.

MEINE_KONSTANTE
FARBE_FRAME_ROT

Variablen werden mit vorgestellten Typcodes geschrieben, z. B. "$array_pixelwert" oder "$string_vorname".

Variablen sollten mit möglichst geringem Geltungsbereich definiert werden. In PHP lassen sich eigentlich nur globale und lokale Variablen unterscheiden. Lokale Variablen gelten dabei nur innerhalb der Struktur, in der sie definiert wurden - normalerweise ist das eine Prozedur oder Funktion. Globale Variablen sollten im HEAD-Bereich der HTML-(PHP)-Datei definiert werden. Um globale von lokalen Variablen anhand des Namens unterscheiden zu können, kann man ihrem Namen den Buchstaben "s" (für Skript" voranstellen.

Wie schon bei den Variablen wird auch bei Prozeduren und Funktionen ein möglichst vollständiger, beschreibender Name mit mehreren Wörtern benutzt. Da Funktionen immer irgendeine Aufgabe ausführen, sollten sie mit einem Verb beginnen.

schliesse_datei
init_array

Mit Kommentaren wird Quelltext lesbarer und für die spätere Weiterbearbeitung wie auch bei der Fehlersuche leichter handhabbar. Kommentare in PHP werden nicht an den Webbrowser weitergeleitet, sodass unbesorgt auch serverseitige Details beschrieben werden können. Nur echte HTML-Kommentare gelangen bis zum Nutzer. Dort wird dann der Name des Autors oder Betreibers übermittelt. Da die Kommentare über das Internet nicht übertragen werden, spielt es keine Rolle, ob sie 5 oder 50 KB gross sind.

Jede Prozedur sollte mit einer kurzen Zweckbeschreibung beginnen. Es sollten alle globalen Variablen, Objekte und anderen Elemente genannt werden, die innerhalb der Prozedur genutzt werden. Es sollte auch jede externe Variable oder jedes externe Objekt genannt werden, das innerhalb der Prozedur geändert wird. Schliesslich sollte die Struktur und der Wertebereich der Rückgabewerte bei Funktionen beschrieben werden.

Am Beginn des Skripts sollte eine kurze Beschreibung der Funktionalität stehen.Auf komplexe Algorithmen kann hingewiesen werden. Bei grösseren Projekten ist es sinnvoll, den Namen des Autors, das Datum der Freigabe und die Versionsfolge zu beschreiben.

Formatierung und Strukturierung

Zur Verbesserung der Lesbarkeit empfiehlt sich die Strukturierung des Codes durch Einrückungen. Das folgende Beispiel zeigt, wie gute Codestrukturierung und Kommentierung aussehen sollte.

Die Zeilenlänge sollte 80 Zeichen nicht überschreiten, um die Skripte auch jederzeit in auf der Konsole mit Standardeinstellungen bearbeiten zu können. Aus diesem Grund sollten auch die Einrückungen jeweils bloss aus zwei oder höchstens vier Leerschlägen bestehen.

Die Variablennamen sollten sich selber erklären. Einfache Zähl- oder Hilfsvariablen werden üblicherweise nicht mit beschreibenden Namen bedacht; für Zählvariablen hat sich die Buchstabengruppe i, j, k usw. eingebürgert. Für die Zwischenspeicherung von numerischen Werten werden oft a, b, c oder x, y, z verwendet.

/*******************************************************************************
 * Funktion     Ermittelt den ersten Namen im Array "userlist".
 * Eingabe      $string_userlist: Liste der zu durchsuchenden Namen
 *              $string_targetuser: Der zu suchende Name
 * Ausgabe      Der Index des ersten gefundenen Namens im Array "userlist".
 *              Wird nicht so gefunden, so wird -1 zurückgegeben.
 ******************************************************************************/

function integer_finduser($string_userlist, $string_targetuser)
{
  $boolean_found    = false;     ## true, wenn gefunden
  $integer_finduser = -1;
  $i                = 0;         ## Initialisiere Zähler
  while ($i <= count($string_userlist) && !$boolean_found)
  {
    if ($string_userlist[$i] == $string_targetuser)
    {
      $boolean_found = true;     ## Gefunden, true setzen
      return $i;                 ## Rückgabewert = Zähler
    }
    i++;                         ## Nächster Index
  }
}

Für die Lesbarkeit des Quelltexts ist auch die saubere Trennung von HTML-Code und PHP-Skript wichtig. Bei komplexen Anwendungen entsteht schnell ein unnötiges Durcheinander von Befehlen. Befinden sich wenige PHP-Skriptbefehle innerhalb des HTML-Codes, so sollte jeder Befehl auf eine Zeile gesetzt werden und jeweils einzeln mit den Tags "<?php" und "?>" umgeben werden.

<body>
<h1>Codeanordnung</h1>
<?php
if ($name == "admin")
{
  echo "Hier die <b>internen</b> Codes.<br />\n";
} 
else
{
  echo "Hier die öffentlichen Codes.<br />\n";
}
?>
</body>

Im allgemeinen sollte "echo" nicht verwendet werden, um viel HTML-Code auszugeben. Besser ist es, die umgebenden Skriptbefehle in einzelne "<?php ... ?>"-Codes zu setzen. Wenn es sich nicht vermeiden lässt oder die Lesbarkeit dadurch nicht besser wird, so kann HTML-Code in Konstanten gepackt werden, was vor allem bei Tabellenstrukturen vorkommt. Das folgende Beispiel nutzt diese Möglichkeit und definiert eine Art "Supertag".

<?php
define("TABBEGIN", "<tr><td><font size='4'>");
define("TABEND",   "</font></td></tr>\n");
?>
<table border=1>
<?php
$string_laufwerkname = "A";
$end = 1;
for($i = 0; $i < $end; $i++)
{
  echo TABBEGIN;
?>
Laufwerksbuchstabe:
<?php
  echo $string_laufwerkname . TABEND;
}
?>
</table>
Laufwerksbuchstabe: A

Schwer lesbar sind auch lange Variablennamen. Vor allem im Datenbankbereich kommen komplexe SQL-Abfragen vor. Der folgende Befehl erstreckt sich über mehrere Zeilen, wenn er direkt angewendet wird.

<?php
$query = "SELECT name, partner, firma, vorwahl, telefon FROM namen, firmen, kommunikation WHERE kommunikation.vorwahl BETWEEN '08' AND '08999' GROUP BY NAME";
?>

Besser sieht es aus, wenn die Struktur des SQL-Befehls klar erkennbar ist.

<?php
$query  = "SELECT name, partner, firma, vorwahl, telefon";
$query .= " FROM namen, firmen, kommunikation";
$query .= " WHERE kommunikation.vorwahl BETWEEN '08' AND '08999' GROUP BY NAME";
?>

Abfrage von Zuständen

Um mitten im Code zu erfahren, wie der Inhalt einer Variable oder der Zustand einer Funktion ist, werden "echo"-Befehle eingefügt. Diese Stellen sollten gekennzeichnet werden, sodass die Angaben später leicht entfernt werden können.

echo $test;     # debug

In sehr grossen Projekten bietet es sich an, diese Fehlerausgaben zentral ein- oder ausschalten zu können. Die Ausgaben können dann mit "$debug = true;" eingeschaltet und mit "$debug = false;" ausgeschaltet werden.

if ($debug) { echo $test; }

Sinnvoll ist auch die Nutzung der folgenden bereits vorgestellten Funktionen.

Funktion Beschreibung
empty Prüft, ob eine Variable leer ist.
isset Prüft, ob eine Variable bereits initialisiert wurde.
is_array Prüft, ob die Variable ein Array ist (kann auch leer sein).
is_double
is_float
is_real
Diese Funktionen geben "TRUE" zurück, wenn die Variable einen Gleitkommawert enthält.
is_int
is_integer
is_long
Diese Funktionen geben "TRUE" zurück, wenn die Variable eine Ganzzahl enthält.
is_object Diese Funktion gibt "TRUE" zurück, wenn die Variable ein Objekt enthält.
is_string Diese Funktion gibt "TRUE" zurück, wenn die Variable eine Zeichenkette enthält.
is_resource Diese Funktion gibt "TRUE" zurück, wenn die Variable ein Handle auf eine Resource enthält.
gettype Ermittelt den Datentyp, der in der Form "string", "object" usw. ausgegeben wird.

Zum professionellen Arbeiten mit PHP empfiehlt sich die Nutzung einer Integrierten Entwicklungsumgebung / IDE mit Debugger. Das ist hilfreich, um zur Laufzeit Informationen über Variablen, die Reaktion von Methoden und aktuelle Ausgaben zu erhalten, bevor Daten an den Webbrowser gesendet werden.

Mit der Funktion "function_exists" kann das Vorhandensein von Funktionen abgefragt werden, was vor allem in der Testphase nützlich sein kann, wenn eingebundene Funktionen und externe Bibliotheken kontrolliert werden müssen. Die Anwendung dieser Funktion eignet sich vor allem in Skripten, die für ältere PHP-Versionen entwickelt wurden. Wenn das Skript auf einem neueren PHP zum Einsatz kommt, sollte die eingebaute Funktion genutzt werden. Läuft das Skript dagegen mit einem älteren, so gibt die Funktion "function_exists" den Wert "FALSE" zurück. Innerhalb des "if"-Zweigs wird dann eine Ersatzfunktion definiert.

<?php
function myfunction() 
{
  ## Pseudofunktion
}

if (function_exists("myfunction")) 
{ 
  echo "Funktion 'myfunction' ist definiert"; 
}
?>
Funktion 'myfunction' ist definiert