Geschwindigkeit von PHP-Scripts optimieren

Folgende Aufzählung enthält Tipps und Tricks zur Steigerung der Ausführungsgeschwindigkeit von PHP-Scripts.

1. "Identisch" ist schneller als "gleich"

<?php
if ($a == $b) { }
// unteres ist schneller als oberes
if ($a === $b) { }
?>

Dasselbe gilt auch für != vs !==.

gleich:    15.5 ms
identisch:  9.0 ms

2. "Identisch" ist schneller als "nicht identisch"

<?php
if ($a === true) { }
// oberes ist schneller als unteres
if ($a !== false) { }
?>
identisch:        8.5 ms
nicht identisch:  9.5 ms

Bei einem einfachen "gleich" (== bzw. !=) ist kaum ein Unterschied festzustellen.

3. "Kleiner gleich" ist schneller als "kleiner als"

<?php
if ($i < 10) { }
// unteres ist schneller als oberes
if ($i <= 9) { }
?>
kleiner als:     16.0 ms
kleiner gleich:  14.5 ms

Andersherum ist "grösser als" ist leicht schneller als "grösser gleich".

<?php
if ($i > 9) { }
// oberes ist schneller als unteres
if ($i >= 10) { }
?>
grösser als:     14.4 ms
grösser gleich:  15.0 ms

4. Der Trinitäts-Operator ist schneller als ein einfaches if-else-Statement

<?php
if ($b) { $a = $c; }
else { $a = $d; }
// unteres ist schneller als oberes
$a = ($b) ? $c : $d;
?>
if-else-Statement:   18.3 ms
Trinitäts-Operator:  11.5 ms

5. Fehlermeldungen nicht mit einem @ unterdrücken

<?php
// nicht so:
@unlink('mich-gibts-nicht.dat');
// sondern so:
if (file_exists('mich-gibts-nicht.dat'))
    unlink('mich-gibts-nicht.dat');
?>

6. Fehlermeldungen, Notices und Strict-Standards nicht unterdrücken, sondern verhindern

<?php
// nicht so:
$wert = array_shift(explode($str, $array)); // erzeugt eine Strict-Meldung
// sondern so:
$werte = explode($str, $array));
$wert = array_shift($werte);
// ----
// nicht so:
if ($gibtsnicht) { } // erzeugt eine Notice
// sondern so:
if (isset($gibtsnicht)) { }
?>

Fehlermeldungen jeglicher Art, ob sie unterdrückt werden oder nicht, verlangsamen das Script.

7. (int) ist mehr als doppelt so schnell wie intval()

<?php
$zahl = intval($str);
// unteres ist schneller als oberes
$zahl = (int)$str;
?>

intval() bietet noch eine zusätzliche Funktion, welche jedoch meist nicht benutzt wird.

intval():  53 ms
(int):     25 ms

8. Einfache Anführungszeichen und Stringverkettung benutzen

<?php
echo "Ich heisse $name";
// unteres ist schneller als oberes
echo 'Ich heisse '.$name;
?>

Da PHP bei doppelten Anführungszeichen den String nach Variablen durchsucht, geht da Zeit verloren.

doppelt:  82 ms
einfach:  70 ms

9. echo ist schneller als print

<?php
echo 'Text';
// oberes ist schneller als unteres
print 'Text';
?>

print hat im Gegensatz zu echo einen Rückgabewert, doch dieser ist im Grunde nutzlos.

echo:   23 ms
print:  31 ms

10. Stringverkettung ist langsamer als mehrere echos (bei mehreren Variablen)

<?php
echo $var1.$var2.$var3.$var4.$var5;
// unteres ist geringfügig schneller als oberes
echo $var1; echo $var2; echo $var3; echo $var4; echo $var5;
echo $var1, $var2, $var3, $var4, $var5;
?>

Wenn nur mehrere Strings (keine Variablen) ausgegeben werden, gibt es keinen Unterschied.

Verkettung:     25 ms
mehrere echo:   20 ms
Komma-getrennt: 20 ms

11. array_map() ist schneller als foreach

<?php
$array = array_map('funktion', $array);
// oberes ist schneller als unteres
foreach($array as &$value)
    $value = funktion($value);
?>

Bei Arrays mit weniger als 15 Elementen empfiehlt es sich jedoch foreach zu benutzen.

array_map():  72 ms
foreach:      90 ms

Anmerkung: Der effektive Unterschied der Geschwindigkeit der beiden Methoden ist von der Funktion abhängig, welche auf die Array-Werte angewendet wird.

12. Funktionen innerhalb von Schleifen-Parametern sind sehr kostspielig

<?php
// nicht so:
for ($i = 0; $i < count($array); $i++) { }
// sondern so:
$total = count($array);
for ($i = 0; $i < $total; $i++) { }
?>
oberes:   53 ms
unteres:  18 ms

Bei der oberen Methode muss die Funktion (hier count()) pro Durchgang einmal ausgeführt werden, bei der unteren wird sie insgesamt nur einmal aufgerufen.

13. $i++ ist schneller als $i+=1

$i++:   8.5 ms
$i+=1:  9.5 ms

14. $array[] ist schneller als array_push()

<?php
$array[] = 'value';
// oberes ist schneller als unteres
array_push($array, 'value');
?>
$array[]:      60 ms
array_push(): 102 ms

15. strtr() ist schneller als str_replace(), dieses ist schneller als preg_replace()

... und dieses wiederum ist schneller als ereg_replace(), allerdings empfiehlt es sich, ganz auf ereg-Funktionen zu verzichten.

16. Benutze unset() um den Speicher wieder freizugeben

Dies lohnt sich allerdings nur bei grösseren Variablen wie längeren Strings oder Arrays.

Bei MySQL-Daten kann man mysql_free_result() verwenden.

17. Includes (include(), require()) sollten wenn möglich verhindert werden

Jeder Include verursacht ein erneuter Zugriff auf das Dateisystem und somit zusätzliche Festplattenaktivität. Des weiteren muss der PHP-Parser nochmal ans Werk.

Falls eine nicht-PHP-Datei eingebunden werden muss, empfiehlt es sich readfile() zu benutzen.

18. htmlspecialchars() ist schneller als htmlentities()

Wenn man nur die HTML/XML-Steuerzeichen als Entities kodieren will, ist es angebracht htmlspecialchars() zu verwenden.

htmlspecialchars():  80 ms
htmlentities():     150 ms

Der Geschwindigkeitsunterschied ist nachvollziehbar.

19. Optionaler Parameter nicht an Funktion übergeben, wenn er dem Standard-Wert entspricht

<?php
function func($a=1, $b=2, $c=3) {
    // Beispiel-Funktion mit optionalen Parametern
}
// Aufruf ohne Parameter:
func();
// Aufruf mit den Standard-Werten:
func(1, 2, 3);
?>

Die beiden Aufrufe machen genau das gleiche, doch ist die obere Variante ohne Parametern schneller.

func():     12.5 ms
func(...):  14.5 ms

Testmethode

Die Tests wurden unter Windows XP bei PHP 5.2.3 durchgeführt, mittels einer for-Schleife mit 100'000 oder 10'000 Durchläufen. Die Werte sind Durchschnittswerte von ca. 30 Einzel-Ergebnissen. Von den Werten wurde jeweils die Leerlaufzeit der for-Schleife abgezogen.

Kommentar

In den meisten Fällen ist Leserlichkeit des Codes wichtiger als Geschwindigkeit, deshalb sei es gut überlegt ob man Code durch performanteren aber weniger leserlichen ersetzt.