for, while und foreach – Performance verbessern mit der richtigen Schleife

Beim Durchlaufen von Arrays bietet PHP unterschiedliche Möglichkeiten. Die richtige Wahl hängt unter anderem davon ab, ob nur auf den Array-Wert oder auch auf den Key zugegriffen werden muss. Während foreach() eine Kopie des Arrays anfertigt, muss bei while()-Schleifen der „Zeiger” mit reset() zurückgesetzt werden. Die for()-Schleife zum Durchlaufen von Arrays ist nur dann sinnvoll einzusetzen, wenn nur auf die Werte, nicht auf die Schlüssel des Arrays zugegriffen werden soll.

foreach()-Schleife mit Key

Code:

<?php
for ($i = 0;$i < 100;$i++) {
    $test[$i] = "Beispiel";
}
for ($i = 0;$i < 100;$i++) {
    foreach ($test as $key => $value) {
        echo $value;
    }
}
?>

Erläuterung:
In diesem ersten Beispiel-Code soll neben den Array-Werten auch auf die Schlüssel zugegriffen werden. Innerhalb einer for()-Schleife wird zunächst ein Array namens $test mit 100 Werten angelegt. In der zweiten for()-Schleife wird das Array 100mal Durchlaufen. Dabei wird mit foreach() auch auf den Key zugegriffen. Mittels echo wird jedoch nur der Wert ausgegeben.

while()-Schleife mit Key

Code:

<?php
for ($i = 0;$i < 100;$i++) {
    $test[$i] = "Beispiel";
}
for ($i = 0;$i < 100;$i++) {
    reset($test);
    while (list($key, $value) = each($test)) {
        echo $value;
    }
}
?>

Erläuterung:
Das zweite Beispiel-Script ist gemessen an der Funktionalität mit dem ersten Script identisch. Auf Array-Key und -Wert wird in der zweiten for()-Schleife jedoch nicht mehr mit foreach(), sondern mit while() und list() zugegriffen. Zuvor wird der beim Anlegen und Durchlaufen des Arrays von PHP verwendete „Zeiger” mit reset() zurückgesetzt. Dies war bei der foreach()-Schleife nicht erforderlich, da foreach() automatisch eine Kopie des Arrays anfertigt und der Zeiger somit praktisch keine Rolle spielt.

foreach()-Schleife ohne Key

Code:

<?php
for ($i = 0;$i < 100;$i++) {
    $test[$i] = "Beispiel";
}
for ($i = 0;$i < 100;$i++) {
    foreach ($test as $value) {
        echo $value;
    }
}
?>

Erläuterung:
Dieses dritte Beispiel-Script ist von der Funktionalität her identisch mit dem ersten Script. Im Unterschied dazu wird mit der foreach()-Schleife jedoch nicht mehr auf den Schlüssel des Arrays zugegriffen, sondern nur noch auf den via echo ausgegebenen Wert.

while()-Schleife ohne Key

Code:

<?php
for ($i = 0;$i < 100;$i++) {
    $test[$i] = "Beispiel";
}
for ($i = 0;$i < 100;$i++) {
    reset($test);
    while ($value = next($test)) {
        echo $value;
    }
}
?>

Erläuterung:
Auch das Beispiel-Script mit der while()-Schleife wurde dahingehend modifiziert, dass kein Zugriff mehr auf den Array-Key erfolgt. Dabei wird für die while()-Schleife nicht mehr list() und each(), sondern das schnellere next() verwendet.

for()-Schleife

Code:

<?php
for ($i = 0;$i < 100;$i++) {
    $test[$i] = "Beispiel";
}
for ($i = 0;$i < 100;$i++) {
    for ($j = 0;$j < 100;$j++) {
        echo $test[$j];
    }
}
?>

Erläuterung:
Der Code bewirkt das gleiche wie die beiden vorangegangenen Codes. Das Array wird nicht mehr mittels foreach() oder while() durchlaufen, sondern die einzelnen Array-Werte direkt anhand ihres Schlüssels angesprochen und via echo ausgegeben. Diese Vorgehensweise ist nur sinnvoll, wenn es sich bei den Array-Schlüsseln um Zahlen handelt und der Zugriff auf den Schlüssel nicht nötig ist. Letzteres ist ohnehin der Fall, weil uns die Array-Schlüssel in dieser Variante bekannt sein müssen, um auf die Werte zugreifen zu können.

Ergebnis

Requests per second (RPS)Time per Request (TPR)Vergleich
foreach()-Schleife mit Key105.61 [#/sec] (mean)9.469 [ms] (mean)
137.3%
57.9%
while()-Schleife mit Key44.51 [#/sec] (mean)22.469 [ms] (mean)
foreach()-Schleife ohne Key125.74 [#/sec] (mean)7.953 [ms] (mean)
182.5%
64.6%
while()-Schleife ohne Key89.01 [#/sec] (mean)11.234 [ms] (mean)
100.0%
50.0%
for()-Schleife125.24 [#/sec] (mean)7.984 [ms] (mean)
181.4%
64.5%

Bei jedem durchgeführten Benachmark waren die Varianten mit foreach() deutlich schneller als die while()-Schleifen verwendenden. Die Variante mit for() war in einigen Fällen die schnellste.

Fazit

Gemessen an der Geschwindigkeit sind beim Durchlaufen von Arrays foreach()-Schleifen den while()-Schleifen in jedem Fall vorzuziehen. Der Einsatz einer for()-Schleife ist nicht in jedem Fall sinnvoll und nur unwesentlich schneller als die foreach()-Variante. Nicht beachtet bei den Benchmarks wurde jedoch die Speichernutzung.

 

Anmerkung:
Die Tests wurden mit dem Apache HTTP server benchmarking tool ab auf einem im Februar 2017 nicht mehr dem Stand der Technik entsprechenden Server durchgeführt. Die RPS und TPR der getesteten PHP-Scripte sollten auf einem im Produktiv-Einsatz befindlichen Webserver deutlich besser sein.

Nächster Tipp: