Programmiert sauber! Auch für die Performance

PHP ist recht tolerant, was Datentypen angeht – meist werden die Daten so umgewandelt, wie sie gebraucht werden. Das führt aber leider auch zu unsauber programmierten Scripten, die zwar korrekt ausgeführt werden, aber bei denen PHP erst raten muss, was der Programmierer wirklich gemeint hat. Deshalb habe ich mal getestet, inwiefern unsauber programmierte Scripte sich auch auf die Performance auswirken.

Dieser Beitrag wurde inspiriert vom Themenvorschlag von Bill, der sich einige fertige Scripte näher angesehen und festgestellt hat, dass viele unsauber programmiert sind. Insbesondere auffällig sind der Arrayzugriff auf assoziative Arrays, wobei der Arrayschlüssel fälschlicherweise ohne Anführungszeichen angegeben wird.

echo $arr[index];

PHP sucht dann erstmal nach einer Konstante mit dem Namen index. Sollte diese nicht existieren, wandelt es den Token index in einen String um und versucht den Arrayzugriff danach noch einmal. Im Prinzip ist es bei der unsauberen Variante also der doppelte Aufwand.
Nebenbei wird noch ein Fehler vom Typ E_NOTICE ausgegeben, allerdings werden diese oft weder angezeigt noch geloggt.

Um zu testen, wie sehr sich unsaubere Programmierung auf die Performance auswirkt, habe ich folgende beiden Scripte gegeneinander antreten lassen:

// Richtig 
  $arr = array('farbe'=>'rot','zustand'=>'neu');
  echo $arr['farbe'];
  // Falsch
  $arr = array(farbe=>rot,zustand=>neu);
  echo $arr[farbe];
  

Das ganze habe ich jeweils 1000 mal durchlaufen lassen, um einen geeigneten Mittelwert ohne größere Abweichungen zu erhalten. Das Ergebnis:

Test durchschnittliche Laufzeit pro Durchlauf Verhältnis zur schnellsten Variante
Richtig 8.131 ms 100%
Falsch 17.455 ms 215% (+115%)

Die unsaubere Variante benötigt demzufolge mehr als doppelt so viel Zeit wie die saubere. Es ist also sehr zu empfehlen solche „verdeckten“ Fehler auszubessern, auch aus Performancegründen.

Weitere Beispiele solcher Fehler sind Funktionsübergaben, wie z.B.

  date(d.m.y); 
  echo Hallo;
  

Solche Fehler lassen sich übrigens sehr einfach entdecken, ohne dass man jedes Script Zeile für Zeile durchsuchen muss. Einfach das PHP Error-Log in der php.ini aktivieren (log_errors = On) und alle Fehler aufzeichnen (error_reporting = E_ALL). Der Pfad zur Logdatei kann mittels error_log festgelegt werden. Im Log sieht man dann alle Fehler inklusive dem Scriptnamen und der Zeilennummer.

Ein bisschen Off-Topic aber eben doch zum Thema Datentypen möchte ich mich noch über folgendes beschweren: Aus Sicherheitsgründen sollte man ja alle Ein- und Ausgaben filtern. Für numerische Eingaben gibt es da die tolle Funktion ctype_digit, die überprüft, ob die übergebene Zeichenkette ausschließlich aus Ziffern besteht. Dumm nur, dass die Funktion nur funktioniert, wenn man ihr einen String übergibt. Übergibt man z.B. eine int-variable, interpretiert die Funktion die Zahl als ASCII-Code. Deshalb liefert ctype_digit(5) = false und ctype_digit(48) = true (ASCII 48 bis 57 entsprechen 0 bis 9)!
Manche mögen sagen, dann nutzt man eben intval oder is_numeric, allerdings ist das für Postleitzahlen z.B. nicht möglich, da dann bei intval solche, die mit Null beginnen einfach auf 4 Stellen gekürzt werden (aus 01234 wird 1234) und bei is_numeric weitere Eingaben als valide angesehen würden wie +0123.45e6. Also wer die Funktion ctype_digit benutzt, sollte peinlich genau darauf achten, ihr immer Strings zu übergeben oder eine Wrapper-Funktion erstellen, die die Variable in einen String umwandelt und dann ctype_digit aufruft.
Aber das nur am Rande…

Habt ihr noch Beispiele, wo PHP aufgrund seiner Toleranz Datentypen gegenüber Probleme macht bzw. eurer Meinung nach zu tolerant ist?


Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0