foreach Schleife in Php
Sie befinden sich:
Home >
Php >
foreach Schleife in Php
Sobald mehr als ein Wert zusammengehört, kommt die PHP foreach Schleife ins Spiel. Sie läuft ohne Zählvariable durch jedes Element eines Arrays und ist damit die einfachste und sicherste Art, eine Liste abzuarbeiten. Dieser Artikel zeigt die Arbeit mit Schlüsseln und Werten, verschachtelte Arrays, Referenzen, Generatoren sowie die Fallen, in die Einsteiger dabei regelmäßig tappen.
foreach (array as $wert) Ausdruck (z. B. echo $wert;)
foreach (array as $key => $wert) Ausdruck (z. B. echo $wert;)
Die erste Funktion schreibt bei jedem Durchlauf des Arrays das aktuelle Element in die Variable $wert, und
inkrementiert (erhöhen um eins) den internen Zeiger auf das Array um eins, um auf das nächste
Element zugreifen zu können.
Die zweite Variante der foreach-Schleife gleicht grundsätzlich der ersten, jedoch
wird zusätzlich zum Feldinhalt auch der Feldname (Schlüssel) an die Variable $key übergeben. Dies
ist dann sinnvoll, wenn es sich um ein Array mit assoziativen Feldindizes
handel.
Der interne Zeiger auf das entsprechende Array wird beim Aufruf von foreach(); automatisch
auf das erste Element gesetzt, so, dass ein zusätzlicher Aufruf von reset(); entfallen
kann.
Seit PHP 7 arbeitet foreach direkt auf dem Original-Array, wenn &$wert verwendet wird.
Möchte man Werte im Array ändern, verwendet man die Referenz-Schreibweise
(foreach ($array as &$wert)), wie im folgenden Beispiel gezeigt.
Das folgende Beispiel erläutert die grundlegende Funktionsweise:
<?php
$feld_eins = array(1, 2, 3, 4);
/**
* Das & Zeichen vor $wert muss verwendet
* werden damit der Wert des Elements verändert
* werden kann.
**/
foreach ($feld_eins as &$wert) {
$wert = $wert * 2;
}
/**
* $feld_eins hat nun folgenden Inhalt (2, 4, 6, 8)
**/
/**
* Ein weiteres Beispiel dieses Mal
* für ein zweidimensionales Array
**/
$feld_zwei = array();
/**
* eine für PHP ungewöhnliche
* Zuweisung für Felder eines Arrays
**/
$feld_zwei[0][0] = "a";
$feld_zwei[0][1] = "b";
$feld_zwei[1][0] = "y";
$feld_zwei[1][1] = "z";
foreach ($feld_zwei as $wert1) {
foreach ($wert1 as $wert2) {
echo $wert2;
}
}
/**
* für assoziative Arrays, die Ausgabe
* bezieht sich hier auf die Indizes z.B. "a"
**/
$feld_drei = array("a"=>"1","b"=>"2", "c"=>"3","d"=>"4");
foreach ($feld_drei as $key =>$wert_3) {
echo $key; /* abcd */
}
?>
Erklärung:
Mithilfe des Schlüsselwortes „foreach“ können wir durch ein Array
gehen. Wir können einen bestimmten Wert auslesen oder aber auch verändern. Im
ersten Beispiel haben wir ein eindimensionales Array namens „$feld_eins“ mit den
Werten (1,2,3,4). Dann haben wir den Befehl „foreach“ verwendet, um jeden Wert
im Array zu verdoppeln. Damit der Wert des Elements verändert werden kann, müssen
wir ein &-Zeichen vor $wert setzen. Nachdem wir den Befehl ausgeführt haben, hat
das Array den Inhalt (2,4,6,8).
Im zweiten Beispiel haben wir ein zweidimensionales Array namens „$feld_zwei“.
Hier haben wir eine für PHP ungewöhnliche Zuweisung verwendet, indem wir die Werte
des Arrays direkt zugewiesen haben. Der Inhalt dieses Arrays ist: ("a", "b", "y", "z"). Wir
haben wieder den Befehl „foreach“ verwendet, um jeden Wert im Array auszulesen
und auf dem Bildschirm auszugeben.
Im dritten Beispiel haben wir ein assoziatives Array namens „$feld_drei“. Da es
sich hierbei um ein assoziatives Array handelt, steht der Schlüssel neben dem Wert. Der
Inhalt des Arrays ist: ("a"=>"1", "b"=>"2", "c"=>"3", "d"=>"4"). Auch hier wurde
wieder der Befehl „foreach“ verwendet, um jeden Wert im Array auszulesen und auf
dem Bildschirm auszugeben.
foreach ist schneller und einfacher als eine vergleichbare while-Schleife. Das folgende Beispiel
zeigt die empfohlene Vorgehensweise mit foreach:
Hinweis: Die früher verwendete Kombination aus while(), list() und each() ist
seit PHP 8.0 nicht mehr verfügbar, da each() entfernt wurde. Verwenden Sie stattdessen
immer foreach:
<?php
/**
* der interne Zeiger wird automatisch durch den Aufruf auf
* das erste Element gesetzt
**/
foreach($feld as $key => $wert){
$feld[$key] = $wert + 1;
}
?>
Man sollte vor dem Ausführen einer foreach Schleife, die Variable mit dem PHP Befehl is_array()
prüfen, da ansonsten eine Fehlermeldung ausgegeben wird, wenn die Variable kein Array
ist.
Fehlerbehandlung in der PHP foreach Schleife
Seit PHP 8.0 wirft foreach einen TypeError, wenn die
übergebene Variable kein Array und kein Traversable-Objekt ist.
Dieser Fehler kann mit einem try-catch-Block gefangen werden:
<?php
try {
foreach ($daten as $element) {
/* Code hier ausführen */
}
} catch (\TypeError $e) {
echo 'Fehler: ' . $e->getMessage();
}
?>
Empfohlene Vorgehensweise: Prüfen Sie die Variable vor dem
foreach-Aufruf mit is_iterable() oder is_array(),
anstatt Fehler erst zur Laufzeit abzufangen:
<?php
if (is_iterable($daten)) {
foreach ($daten as $element) {
/* Code hier ausführen */
}
}
?>
Die PHP foreach Schleife mit Schlüssel und Wert
Bislang haben Sie foreach nur über die Werte eines Arrays laufen lassen. In der Praxis brauchen Sie aber sehr oft auch den dazugehörigen Schlüssel, zum Beispiel bei assoziativen Arrays mit sprechenden Indizes. Genau dafür gibt es die Variante foreach ($arr as $key => $value). PHP packt sich bei jedem Durchgang das Schlüssel-Wert-Paar in zwei separate Variablen.
<?php
declare(strict_types=1);
$preise = [
'Apfel' => 0.45,
'Banane' => 0.30,
'Kirsche' => 1.20,
];
foreach ($preise as $produkt => $preis) {
echo $produkt . ': ' . number_format($preis, 2, ',', '.') . " €
";
}
/* Apfel: 0,45 €
Banane: 0,30 €
Kirsche: 1,20 € */
Der Variablenname links vom Pfeil ist frei wählbar. Sie können ihn nennen, wie Sie wollen, denn PHP weist nur den jeweils aktuellen Schlüssel zu. Genauso funktioniert das auch mit numerisch indizierten Arrays. Dort enthält $key dann den fortlaufenden Index ab Null.
Mehrdimensionale Arrays mit verschachteltem foreach
Daten kommen selten flach daher. Wer Datensätze aus einer Datenbank holt, einen JSON-Stream parst oder eine Konfigurationsdatei einlesen, bekommt fast immer mehrdimensionale Strukturen. Eine verschachtelte foreach-Schleife ist das passende Werkzeug, um durch beliebig tiefe Daten zu wandern. Wichtig ist, dass Sie für jede Ebene eine eigene Laufvariable nutzen, damit Sie sie nicht versehentlich überschreiben.
<?php
declare(strict_types=1);
$bestellungen = [
'Nico' => ['Buch', 'Kaffee'],
'Lena' => ['Maus', 'Tastatur', 'Monitor'],
'Tarek' => [],
];
foreach ($bestellungen as $kunde => $artikel) {
echo $kunde . " bestellt:
";
foreach ($artikel as $position) {
echo ' - ' . $position . "
";
}
}
Wenn Sie die Tiefe Ihrer Struktur vorher nicht kennst, ist eine rekursive Funktion oft sauberer als immer mehr verschachtelte Schleifen. Trotzdem reicht foreach in den meisten Praxisfällen vollkommen aus, weil Datensätze meistens nur zwei Ebenen haben.
Iteration mit Referenz: foreach ($arr as &$item)
In der Standardform arbeitet foreach mit Kopien der Werte. Ändern Sie $item im Schleifenkörper, wird das Original-Array nicht angefasst. Manchmal wollen Sie genau das aber: die Werte direkt im Array verändern. Dafür gibt es das kaufmännische Und vor der Laufvariable.
<?php
declare(strict_types=1);
$zahlen = [1, 2, 3, 4, 5];
foreach ($zahlen as &$zahl) {
$zahl = $zahl * 2;
}
unset($zahl); /* WICHTIG: Referenz aufloesen */
print_r($zahlen);
/* Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 ) */
Der Reference-Bug-Klassiker
Vergisst Sie das unset($zahl) nach der Schleife, lebt die Referenz weiter. Greifen Sie später in einer zweiten foreach-Schleife auf $zahl zu, ohne sie neu zu deklarieren, überschreiben Sie das letzte Element Ihres Arrays. Dieser Bug ist berüchtigt und sehr schwer zu finden, weil der Fehler oft weit weg vom Auslöser auftritt. Mach sich das unset() direkt nach jeder Referenz-Schleife zur Gewohnheit. Mit unset() brichst Sie die Bindung sauber auf.
foreach mit Generator-Funktionen
Eine Funktion mit yield wird zum Generator. Generatoren liefern Werte einzeln, statt das ganze Ergebnis im Speicher aufzubauen. Genau das macht sie ideal für riesige Listen, Dateizeilen oder unendliche Sequenzen. foreach kann über Generatoren laufen, als wären sie ganz normale Arrays.
<?php
declare(strict_types=1);
function bisZahl(int $max): \Generator
{
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (bisZahl(5) as $n) {
echo $n . ' ';
}
/* 1 2 3 4 5 */
Auch yield $key => $value ist erlaubt. Damit können Sie wie bei einem assoziativen Array iterieren, ohne jemals den vollen Datenbestand im RAM zu halten. Das ist besonders praktisch, wenn Sie große Logdateien oder CSV-Exporte verarbeiten.
Destrukturierung: foreach mit list()-Syntax
Seit PHP 7.1 können Sie in foreach direkt entpacken, was Sie brauchen. Das spart eine Menge Boilerplate-Code, wenn Ihre Datenstruktur aus assoziativen Sub-Arrays besteht. Mehr Hintergrund finden Sie im Tutorial zu list().
<?php
declare(strict_types=1);
$users = [
['name' => 'Anna', 'age' => 28],
['name' => 'Bjoern', 'age' => 35],
['name' => 'Carla', 'age' => 41],
];
foreach ($users as ['name' => $n, 'age' => $a]) {
echo $n . ' ist ' . $a . " Jahre alt.
";
}
Sie können auf diese Weise gezielt nur die Felder herausziehen, die Sie in der Schleife wirklich brauchen. Das macht den Schleifenkörper kürzer und besser lesbar. Schreiben Sie trotzdem nur das raus, was im aktuellen Block sinnvoll ist, sonst leidet die Wartbarkeit.
foreach über Iteratoren und IteratorAggregate
Sie können foreach auch auf eigenen Klassen einsetzen. Implementiert eine Klasse das Iterator- oder IteratorAggregate-Interface, behandelt PHP sie wie eine durchlaufbare Sammlung. Das ist die Grundlage für Collections in Composer-Bibliotheken wie Doctrine oder Symfony.
<?php
declare(strict_types=1);
class Tagebuch implements IteratorAggregate
{
/** @var array<string> */
private array $eintraege = [];
public function add(string $text): void
{
$this->eintraege[] = $text;
}
public function getIterator(): ArrayIterator
{
return new ArrayIterator($this->eintraege);
}
}
$buch = new Tagebuch();
$buch->add('Heute foreach gelernt.');
$buch->add('Morgen Generators.');
foreach ($buch as $eintrag) {
echo '* ' . $eintrag . "
";
}
Mit IteratorAggregate sparen Sie sich die fünf Pflicht-Methoden des einfachen Iterator-Interface. Sie delegierst die Iteration einfach an einen ArrayIterator oder einen Generator. Klassen werden so auf einen Schlag mit allen foreach-Features kompatibel.
Die PHP foreach Schleife steuern: break und continue
Manche Iterationen sollen nicht immer das ganze Array durchlaufen. Mit break verlassen Sie die Schleife sofort, mit continue überspringst Sie nur den aktuellen Durchgang und springst zum nächsten Element. Beide Schlüsselworte funktionieren in foreach genauso wie in der for-Schleife oder der while-Schleife.
<?php
declare(strict_types=1);
$kandidaten = ['anna@example.com', '', 'bjoern@example.com', 'noemail'];
foreach ($kandidaten as $eintrag) {
if ($eintrag === '') {
continue; /* leere Eintraege ignorieren */
}
if (!filter_var($eintrag, FILTER_VALIDATE_EMAIL)) {
echo 'Ungueltig, Abbruch bei: ' . $eintrag . "
";
break;
}
echo 'OK: ' . $eintrag . "
";
}
Sie können sogar break 2 oder continue 2 schreiben, um aus einer verschachtelten Schleife eine Ebene tiefer auszubrechen. Setzen Sie das aber sparsam ein, sonst leidet die Lesbarkeit.
Funktionale Alternativen: array_map und array_filter
Nicht jede Iteration braucht ein foreach. Wenn Sie nur transformierst oder filterst, sind array_map() und array_filter() oft kürzer und ausdrucksstärker. Das ist funktionaler Stil und passt gut zu modernen Arrow Functions.
<?php
declare(strict_types=1);
$zahlen = [1, 2, 3, 4, 5, 6];
$verdoppelt = array_map(fn(int $n): int => $n * 2, $zahlen);
$gerade = array_filter($zahlen, fn(int $n): bool => $n % 2 === 0);
print_r($verdoppelt);
print_r($gerade);
Beide Funktionen erzeugen ein neues Array und verändern das Original nicht. Das macht den Code besser testbar und vermeidet Seiteneffekte. Wenn Sie allerdings beim Iterieren mehrere Aktionen kombinieren wollen, etwa loggen, validieren und transformieren, bleibt foreach die übersichtlichere Wahl.
Lifecycle der PHP foreach Schleife
Das folgende Diagramm zeigt, wie PHP intern bei jedem Durchgang vorgeht. Es greift auf den internen Zeiger der Datenstruktur zu, holt ein Element, führt den Body aus und springt weiter, bis es kein nächstes Element mehr gibt.
flowchart TD
A[Datenstruktur] --> B[Pointer auf erstes Element]
B --> C{Element vorhanden?}
C -- Nein --> F[Schleife beenden]
C -- Ja --> D[Element zuweisen]
D --> E[Body ausfuehren]
E --> G[Pointer auf naechstes Element]
G --> C
Bei einem leeren Array entscheidet PHP direkt am ersten Check mit "Nein" und springt ans Ende. Es gibt keinen Fehler, keine Warnung, kein einziger Body-Aufruf. Das ist praktisch, weil Sie sich den expliziten Leer-Check sparen können, sofern Ihr Body-Code tatsächlich nichts zu tun hat, wenn nichts da ist.
Praxisbeispiel: HTML-Tabelle aus einer Liste rendern
Eine der häufigsten Aufgaben mit foreach ist das Rendern tabellarischer Daten. Hier ein typisches Snippet, das Sie in jedem CMS oder Backend wiederfinden. Es nutzen htmlspecialchars() gegen XSS, damit auch Sonderzeichen sauber in das HTML eingebettet werden.
<?php
declare(strict_types=1);
$produkte = [
['name' => 'Tasse', 'preis' => 9.90, 'stock' => 12],
['name' => 'Buch', 'preis' => 24.00, 'stock' => 0],
['name' => 'Stift', 'preis' => 1.50, 'stock' => 250],
];
echo "<table>
";
echo " <tr><th>Name</th><th>Preis</th><th>Lager</th></tr>
";
foreach ($produkte as $p) {
echo ' <tr><td>' . htmlspecialchars($p['name'])
. '</td><td>' . number_format($p['preis'], 2, ',', '.')
. ' €</td><td>' . $p['stock']
. "</td></tr>
";
}
echo "</table>
";
Praxisbeispiel: Summe und Filter in einem Durchlauf
Manchmal wollen Sie in einem einzigen Schleifendurchgang gleich mehrere Ergebnisse berechnen. Das geht mit foreach sehr direkt und Sie sparen sich mehrere Aufrufe von array_filter() oder array_sum().
<?php
declare(strict_types=1);
$rechnungen = [
['betrag' => 49.90, 'bezahlt' => true],
['betrag' => 199.00, 'bezahlt' => false],
['betrag' => 12.50, 'bezahlt' => true],
['betrag' => 80.00, 'bezahlt' => false],
];
$summeOffen = 0.0;
$anzahlOffen = 0;
foreach ($rechnungen as $r) {
if ($r['bezahlt'] === true) {
continue;
}
$summeOffen += $r['betrag'];
$anzahlOffen += 1;
}
echo "Offene Rechnungen: $anzahlOffen
";
echo 'Offener Betrag: ' . number_format($summeOffen, 2, ',', '.') . " €
";
Der Trick: Sie kombinierst Filter und Aggregation in einer einzigen Schleife und vermeiden das mehrfache Durchlaufen desselben Arrays. Bei kleinen Datenmengen ist das egal, bei zehntausenden Zeilen merken Sie den Unterschied sofort.
Die PHP foreach Schleife bei einem leeren Array
Eine häufige Anfängerfrage lautet: Muss ich vor jedem foreach mit empty() oder count() prüfen, ob überhaupt Daten da sind? Die kurze Antwort: Nein. foreach über ein leeres Array ist völlig harmlos, der Body wird einfach nicht ausgeführt. Es gibt keine Notice, keine Warnung, kein Crash.
<?php
$leer = [];
foreach ($leer as $x) {
echo "Das wird niemals ausgegeben.
";
}
echo "Code laeuft normal weiter.
";
Eine Prüfung mit empty() macht trotzdem manchmal Sinn, nämlich wenn Sie eine Alternativausgabe brauchen, etwa "Keine Einträge vorhanden". Dann reicht aber ein einfaches if-else drumherum. Aufpassen müssen Sie nur, wenn Sie etwas anderes als ein Array oder ein iterierbares Objekt übergeben, etwa null. Dann wirft PHP seit Version 8 einen Fehler. Mit dem Null-Coalescing-Operator können Sie in solchen Fällen einen leeren Default setzen: foreach (($daten ?? []) as $eintrag). Häufige Fragen zur foreach SchleifeVier Fragen klären die Stolpersteine, die bei der PHP foreach Schleife am häufigsten auftauchen. 1Wann nehme ich foreach statt for?Immer dann, wenn Sie jedes Element brauchen und der Index egal ist. Die for-Schleife lohnt sich, sobald Sie rückwärts laufen, Schritte überspringen oder mit dem Zähler rechnen wollen. 2Warum wirkt meine Änderung im Array nicht?Weil foreach normalerweise mit Kopien arbeitet. Wer das Original ändern will, braucht eine Referenz mit &$wert und sollte sie danach mit unset() auflösen. 3Wie komme ich an den Schlüssel?Mit der Schreibweise foreach ($arr as $key => $wert). Bei assoziativen Arrays ist das der Regelfall, bei numerischen liefert es den Index. 4Kann ich über Objekte iterieren?Ja. Ohne weiteres Zutun laufen Sie über die öffentlichen Eigenschaften. Wer mehr Kontrolle will, implementiert Iterator oder IteratorAggregate und bestimmt selbst, was durchlaufen wird. 5Wie breche ich eine PHP foreach Schleife vorzeitig ab?Mit break verlassen Sie die Schleife ganz, mit continue springen Sie zum nächsten Element. Bei verschachtelten Durchläufen gibt eine Zahl dahinter an, wie viele Ebenen gemeint sind. Mit diesen Varianten deckt die PHP foreach Schleife nahezu jede Iteration ab, die im Alltag vorkommt. Jetzt weiter zur for-Schleife oder die Sprachreferenz im PHP-Handbuch nachlesen.
weiter zum nächsten Kapitel:
Verstehe die Grundlagen von while-Schleife und do-while-Schleife in PHP
|