Continue und Break

Sehr häufig hat man Schleifen und möchte aber mit dieser Schleife nur einen Fakt feststellen, der möglicherweise gar nicht das Durchlaufen aller Array-Einträge benötigt. Wenn man beispielsweise ein Array mit lauter natürlicher Zahlen hat und überprüfen möchte, ob die Summe aller Zahlen über einem bestimmten Wert liegen. Bei einer solchen Aufgabe kann die Schleife ja abgebrochen werden, wenn der bestimmte Wert überschritten wurde (man beachte, dass es sich um natürliche Zahlen handelt, die nicht negativ sein können). Leider fällt mir kein praxisnäheres Beispiel ein, aber es gibt sicherlich auch in ihrer Anwendung Schleifen, auf die das angewendet werden kann.

Jedenfalls würde man den Quellcode so umsetzen:

$arr = array(1,2,0,4,8,2,5,3,4,4,0,3,9,4,5,3,4);
$summe = 0;
 
// Variante ohne break und continue
foreach($arr as $summand) {
  $summe += $summand;
}
if($summe>40) {
  echo "Die Summe ist größer als 40 !!!";
}
 
// Variante mit break und continue
foreach($arr as $summand) {
  if($summand==0) continue;
  $summe += $summand;
  if($summe>40) {
    echo "Die Summe ist größer als 40 !!!";
    break;
  }
}

continue bedeutet dabei, dass die aktuelle Schleifen-Iteration nicht weiter fortgesetzt wird sondern direkt zum nächsten Wert übergegangen wird. Im Beispiel bedeutet das, dass wenn wir eine 0 im Array vorfinden der Rechner die folgenden Anweisungen in der Schleife gar nicht ausführen muss, da sich die Summe dadurch sowieso nicht verändert. Es kann also direkt mit dem nächsten Durchlauf fortgesetzt werden.
Das break dient dazu, dass wenn wir einen Wert von 40 (oder mehr) erreicht haben, die Schleife abgebrochen wird, denn wir wollen ja nur feststellen, ob der Wert über 40 liegt.
Manche bezeichnen diese Programmierweise als unsauber, allerdings bleibt der Code trotzdem übersichtlich und man weiß, wie es weitergeht.

Die Performancegewinne hängen natürlich von den ersparten Schleifendurchläufen und noch viel mehr von der Komplexität der Operationen ab, die dadurch nicht ausgeführt werden müssen. In diesem Beispiel wird lediglich eine Addition pro eingespartem Durchgang weniger gemacht, das ist keine besonders fordernde Aufgabe. Wenn allerdings im Schleifenkörper viele Funktionen aufgerufen werden und rechenintensive Operationen durchgeführt werden, dann lohnen sich break und continue auch bereits für Schleifen mit einer recht geringen Anzahl von Durchläufen.
Für den Benchmark habe ich ein Array mit 1000 Zufallszahlen zwischen 0 und 9 erzeugt und anschließend überprüft, wann die Summe der Arrayelemente über 100 steigt. Dabei kommen folgende Ergebnisse heraus:

Datei Gesamtlaufzeit durchschnittliche Laufzeit pro Durchlauf Verhältnis zur schnellsten Variante
result_schleife_
continue_break.php
28.260637 s 2.826 ms 100 %
result_schleife_
normal.php
30.53215 s 3.005 ms 106 % (+ 6%)

Wie zu erwarten war, sind die Unterschiede aufgrund der Einfachheit der Addition nicht riesig, aber in „richtigen Anwendungen“ werden wohl auch etwas rechenintensivere Operationen als bloße Additionen durchgeführt, deshalb lohnt sich der Einsatz von break und continue eigentlich immer, denn langsamer als mit allen Iterationen wirds nicht.

Die Quellcodes und die Benchmark-Ergebnisse lönnen zum Nachvollziehen wie immer heruntergeladen werden.

Wenn man in einer Funktion eine Schleife hat, die den Rückgabewert bestimmt, würde ich statt break einfach das return in den Schleifenkörper schreiben, wenn die Bedingung erfüllt ist:

function funktion() {
  for($i=0;$i<1000;$i++) {
    if($i>50) return true;
  }
  return false;
}

Jan hat 152 Beiträge geschrieben

Ein Kommentar zu “Continue und Break

  1. Tim sagt:

    Du könntest alternativ array_sum verwenden. Das sollte etwas schneller sein, als den kompletten Array zu durchlaufen. Mit array_walk und einer globalen Variable ($sum) könnte man auch gute Ergebnisse erzielen, allerdings weiß ich nicht, wie man ein break „emuliert“ (spontan würde mir nur @unset() einfallen und vor dem array_walk auch ein @ – habe das allerdings noch nicht getestet). Ich habe gehört, dass foreach()-Schleifen generell langsamer als Schleifen über while(), for() oder current()/next()/key() sein sollen. Kannst du das bestätigen?

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>