mitmario.dev

Schleifen

PHP Sandbox 3 Min Lesezeit 4 BeispieleLektion 4 von 7

Bis hierher hat jede Zeile deines Codes höchstens einmal gearbeitet. Eine Schleife ändert das: Sie führt denselben Block so lange aus, bis eine Bedingung nicht mehr gilt. Damit werden aus drei Zeilen Code hundert Zeilen Ausgabe.

while, solange die Bedingung gilt

while, solange noch etwas übrig ist
<?php

$guthaben = 100;
$preis = 30;

while ($guthaben >= $preis) {
    $guthaben = $guthaben - $preis;
    echo "Gekauft. Es bleiben $guthaben Euro.\n";
}

echo "Fuer eine weitere Karte reicht es nicht.\n";

while sieht aus wie ein if und verhält sich am Anfang auch so: Bedingung in runden Klammern, Block in geschweiften. Der Unterschied kommt am Ende des Blocks. Ein if ist dann fertig, ein while springt zurück nach oben und prüft noch einmal.

Im Beispiel wird gekauft, solange das Guthaben reicht. Bei 100 Euro und 30 Euro Kartenpreis sind das drei Durchgänge, danach stehen 10 Euro da und die Bedingung gilt nicht mehr.

Der Block muss die Bedingung verändern. Das ist die einzige Regel, die wirklich zählt. Ohne die Zeile, die das Guthaben verringert, wäre die Bedingung nach dem ersten Durchgang genauso wahr wie davor, und die Schleife liefe für immer. Dazu weiter unten mehr.

for, wenn du vorher weißt wie oft

for, wenn du vorher weißt wie oft
<?php

for ($i = 1; $i <= 5; $i++) {
    echo "Durchgang $i\n";
}

echo "Nach der Schleife steht $i drin.\n";

Sehr oft ist der Zähler die ganze Bedingung: einmal von 1 bis 10, für jede der fünf Zeilen, dreimal hintereinander. Für diesen Fall gibt es for, und der Kopf nimmt alle drei Teile auf einmal auf, getrennt durch Semikolons.

Der erste Teil läuft einmal ganz am Anfang und legt den Zähler an. Der zweite ist die Bedingung, die vor jedem Durchgang geprüft wird. Der dritte läuft nach jedem Durchgang und zählt hoch, meistens mit dem ++ aus Lektion 3.1.

Das ist genau dasselbe wie ein while mit einer Zeile davor und einer am Ende. Der Gewinn liegt darin, dass alle drei Teile beieinanderstehen: Wer die Zeile liest, sieht sofort, wo die Schleife anfängt, wo sie aufhört und in welchen Schritten sie geht.

Ein Detail für später: Die Zählvariable lebt nach der Schleife weiter. Im Beispiel steht danach eine 6 darin, denn erst bei diesem Wert war die Bedingung nicht mehr wahr. Im Reiter Debug kannst du ihr dabei zusehen: Nach Aufzeichnen steht die echo-Zeile fünfmal untereinander, mit i=1 bis i=5 als Chip, und an der Zeile nach der Schleife steht i=6.

Welches von beiden also? Die Faustregel: Weißt du beim Hinschreiben, wie oft es sein wird, nimm for. Hängt es von etwas ab, das sich erst während der Schleife entscheidet, nimm while.

Der Fehler um genau eins

Der Fehler um genau eins
<?php

echo "Mit kleiner-gleich:\n";
for ($i = 1; $i <= 3; $i++) {
    echo "  $i\n";
}

echo "Mit kleiner:\n";
for ($i = 1; $i < 3; $i++) {
    echo "  $i\n";
}

echo "Und ab null gezaehlt:\n";
for ($i = 0; $i < 3; $i++) {
    echo "  $i\n";
}

Diese Sorte Fehler hat einen eigenen Namen, weil sie so häufig ist. Zwischen < und <= liegt genau ein Durchgang, und dieser eine Durchgang ist der Unterschied zwischen einer vollständigen Liste und einer, bei der der letzte Eintrag fehlt.

Im Beispiel stehen drei Schleifen untereinander, die sich nur im Kopf unterscheiden: einmal drei Zeilen, einmal zwei, einmal wieder drei, aber mit anderen Zahlen. Sieh dir die Ausgabe genau an, das ist die halbe Lektion. Die andere Hälfte steht im Reiter Debug: Nach der ersten Schleife bleibt i=4 übrig, nach der zweiten i=3. Genau dieser eine Schritt ist der Unterschied zwischen <= und <.

Die dritte Form, von null bis unter die Grenze, sieht am Anfang ungewohnt aus. Sie ist in der Praxis trotzdem die häufigste, denn Listen fangen in PHP bei null an, und das siehst du in der nächsten Lektion.

do while, für den Fall danach

do while läuft mindestens einmal
<?php

$vorrat = 0;

while ($vorrat > 0) {
    echo "while: ein Stueck ausgegeben\n";
    $vorrat--;
}

echo "Der while-Block ist gar nicht gelaufen.\n";

do {
    echo "do while: ein Stueck ausgegeben\n";
    $vorrat--;
} while ($vorrat > 0);

echo "Der do-Block ist einmal gelaufen, obwohl der Vorrat leer war.\n";

do while dreht die Reihenfolge um: erst der Block, dann die Prüfung. Damit läuft der Block mindestens einmal, auch wenn die Bedingung von Anfang an nicht gilt.

Im Beispiel steht beides untereinander, mit einem leeren Vorrat. Das while gibt gar nichts aus, das do while eine Zeile. Genau das ist der ganze Unterschied.

Gebraucht wird es selten, ungefähr immer dann, wenn man etwas erst tun und danach prüfen muss, ob es geklappt hat. Erkennen solltest du es trotzdem, denn das kleine while am Ende ist leicht zu übersehen, und dahinter steht ein Semikolon. Ein Block, dessen schließende Klammer eines braucht, ist dir bisher nur beim match aus Lektion 4.2 begegnet.

Wenn die Schleife nicht aufhört

Jeder baut sie einmal: eine Bedingung, die immer wahr bleibt, weil im Block die Zeile fehlt, die den Zähler weiterdreht. Auf einem echten Server hängt sich das Programm dann auf, bis jemand eingreift.

In diesem Kurs passiert etwas Freundlicheres. Die Maschine, auf der dein Code läuft, gibt jedem Lauf nur ein paar Sekunden: zehn beim Prüfen, dreißig bei einem Befehl, den du selbst tippst. Reißt du diese Grenze, wird der Lauf abgeräumt, und im Terminal steht unter dem, was bis dahin ausgegeben wurde, eine Zeile von der Plattform: Zeitlimit von 10 s erreicht, Prozess beendet. Wenn du sie siehst, such nicht nach einem Tippfehler, sondern nach der Zeile, die deine Bedingung verändern sollte und es nicht tut.

Der Reiter Debug zeigt dir dabei, was schiefgeht. Bau die Schleife oben einmal absichtlich kaputt, nimm die Zeile mit $guthaben - $preis heraus und klick auf Aufzeichnen: In der Liste steht dieselbe Zeile zweitausendmal untereinander, und ab der zweiten hängt an keiner mehr ein Chip. Die Variable, die sich ändern müsste, ändert sich nie, und die Liste hört auf, bevor die Zeit um ist.

Einen Exit-Code hat so ein Lauf übrigens auch, und zwar 124, das Zeichen von timeout für „die Zeit war um”. Du bekommst ihn nur zu sehen, wenn du die Grenze selbst setzt: timeout 5s php index.php > /dev/null; echo $? im Terminal bricht nach fünf Sekunden ab und schreibt die 124 hin. Das > /dev/null wirft die Ausgabe dabei weg, denn um die geht es hier nicht, und eine Schleife, die fünf Sekunden lang schreibt, füllt sonst das ganze Transkript. Ohne eigenes timeout kommt das echo nie an die Reihe, die Plattform beendet die ganze Zeile auf einmal.

Zum Mitnehmen

Zehn Zeilen ausgeben, ohne zehnmal echo zu schreiben. Dafür gibt es while und for, und der Unterschied zwischen beiden ist keine Geschmacksfrage, sondern eine Frage danach, ob du vorher weißt, wie oft.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.