Kontrollstrukturen sind Sprachkonstrukte, die den Ausführungsfluss eines Programms steuern. Sie ermöglichen es, basierend auf bestimmten Bedingungen Code auszuführen, Code zu wiederholen oder zwischen verschiedenen Codeblöcken zu wählen. PHP bietet eine umfassende Sammlung von Kontrollstrukturen, die in diesem Abschnitt behandelt werden.
Die if-Anweisung ist die grundlegendste Kontrollstruktur
und führt einen Codeblock aus, wenn eine Bedingung wahr ist:
<?php
$alter = 25;
if ($alter >= 18) {
echo "Sie sind volljährig.";
}
?>Mit else kann ein alternativer Codeblock ausgeführt
werden, wenn die Bedingung falsch ist:
<?php
$alter = 15;
if ($alter >= 18) {
echo "Sie sind volljährig.";
} else {
echo "Sie sind minderjährig.";
}
?>Mit elseif (oder else if) können mehrere
Bedingungen nacheinander geprüft werden:
<?php
$alter = 15;
if ($alter < 13) {
echo "Sie sind ein Kind.";
} elseif ($alter < 18) {
echo "Sie sind ein Teenager.";
} elseif ($alter < 65) {
echo "Sie sind ein Erwachsener.";
} else {
echo "Sie sind ein Senior.";
}
?>PHP bietet eine alternative Syntax für Kontrollstrukturen, die besonders nützlich für Template-Dateien ist, in denen PHP und HTML gemischt werden:
<?php if ($loggedIn): ?>
<h1>Willkommen zurück, <?= htmlspecialchars($username) ?>!</h1>
<?php elseif ($registered): ?>
<h1>Bitte loggen Sie sich ein.</h1>
<?php else: ?>
<h1>Bitte registrieren Sie sich.</h1>
<?php endif; ?>Diese Syntax verwendet Doppelpunkte (:) anstelle der
öffnenden Klammer und schließende Tags wie endif,
endforeach, endwhile usw. anstelle der
schließenden Klammer.
Die switch-Anweisung ist eine Alternative zu mehreren
if-elseif-Bedingungen, wenn ein einzelner Wert mit
verschiedenen Möglichkeiten verglichen wird:
<?php
$rolle = "redakteur";
switch ($rolle) {
case "admin":
echo "Vollständiger Zugriff";
break;
case "redakteur":
echo "Kann Inhalte bearbeiten";
break;
case "autor":
echo "Kann Inhalte erstellen";
break;
case "benutzer":
echo "Kann Inhalte lesen";
break;
default:
echo "Kein Zugriff";
break;
}
?>case-Block sollte mit einer
break-Anweisung enden, sonst wird die Ausführung in den
nächsten case fortgesetzt (Fall-Through).default-Block wird ausgeführt, wenn kein
case übereinstimmt.switch verwendet lose Vergleiche (==),
keine strikten Vergleiche (===).case-Werte können für denselben Codeblock
verwendet werden:<?php
$tag = 5;
switch ($tag) {
case 1:
case 2:
case 3:
case 4:
case 5:
echo "Arbeitstag";
break;
case 6:
case 7:
echo "Wochenende";
break;
default:
echo "Ungültiger Tag";
}
?>Der match-Ausdruck, eingeführt in PHP 8.0, ist eine
moderne Alternative zu switch mit einigen wichtigen
Unterschieden:
<?php
$status = 404;
$message = match ($status) {
200, 201, 202 => "Erfolg",
400, 401, 403 => "Client-Fehler",
404 => "Nicht gefunden",
500 => "Server-Fehler",
default => "Unbekannter Status"
};
echo $message; // "Nicht gefunden"
?>match verwendet strikte Vergleiche (===),
während switch lose Vergleiche (==)
verwendet.match ist ein Ausdruck und gibt einen Wert zurück.match benötigt keine
break-Anweisungen.match wertet nur den passenden Arm aus.match wirft einen UnhandledMatchError,
wenn kein Arm übereinstimmt und kein default vorhanden
ist.Mit match können auch komplexere Bedingungen ausgewertet
werden:
<?php
$alter = 25;
$kategorie = match (true) {
$alter < 13 => "Kind",
$alter < 18 => "Teenager",
$alter < 65 => "Erwachsener",
default => "Senior"
};
echo $kategorie; // "Erwachsener"
?>Schleifen werden verwendet, um Code wiederholt auszuführen.
Die while-Schleife führt einen Codeblock aus, solange
eine Bedingung wahr ist:
<?php
$i = 1;
while ($i <= 5) {
echo $i . " ";
$i++;
}
// Ausgabe: 1 2 3 4 5
?>Die do-while-Schleife ist ähnlich wie die
while-Schleife, aber die Bedingung wird erst nach der
Ausführung des Codeblocks geprüft. Dadurch wird der Codeblock mindestens
einmal ausgeführt:
<?php
$i = 1;
do {
echo $i . " ";
$i++;
} while ($i <= 5);
// Ausgabe: 1 2 3 4 5
// Auch wenn die Bedingung anfangs falsch ist, wird der Block einmal ausgeführt
$j = 10;
do {
echo "Dieser Text wird ausgegeben, obwohl j > 5";
} while ($j <= 5);
?>Die for-Schleife ist kompakt und wird verwendet, wenn
die Anzahl der Iterationen im Voraus bekannt ist:
<?php
for ($i = 1; $i <= 5; $i++) {
echo $i . " ";
}
// Ausgabe: 1 2 3 4 5
?>Die for-Schleife besteht aus drei Teilen: 1.
Initialisierung ($i = 1) 2. Bedingung
($i <= 5) 3. Inkrement/Dekrement ($i++)
Jeder Teil kann leer sein oder mehrere Ausdrücke enthalten (getrennt durch Kommas):
<?php
for ($i = 0, $j = 10; $i < 10; $i++, $j--) {
echo "i: $i, j: $j <br>";
}
?>Die foreach-Schleife ist speziell für die Iteration
durch Arrays und objekte optimiert:
<?php
// Einfaches Array
$farben = ["rot", "grün", "blau"];
foreach ($farben as $farbe) {
echo $farbe . " ";
}
// Ausgabe: rot grün blau
// Assoziatives Array mit Schlüssel-Wert-Paaren
$person = [
"name" => "Max Mustermann",
"alter" => 30,
"beruf" => "Entwickler"
];
foreach ($person as $schlüssel => $wert) {
echo "$schlüssel: $wert <br>";
}
// Ausgabe:
// name: Max Mustermann
// alter: 30
// beruf: Entwickler
?>Schleifen können ineinander verschachtelt werden:
<?php
// Multiplikationstabelle von 1 bis 5
for ($i = 1; $i <= 5; $i++) {
for ($j = 1; $j <= 5; $j++) {
echo $i * $j . "\t";
}
echo "<br>";
}
?>PHP bietet Anweisungen zur Steuerung des Schleifenverhaltens:
Die break-Anweisung beendet die aktuelle Schleife
sofort:
<?php
for ($i = 1; $i <= 10; $i++) {
if ($i == 5) {
break; // Beendet die Schleife, wenn $i 5 erreicht
}
echo $i . " ";
}
// Ausgabe: 1 2 3 4
?>Bei verschachtelten Schleifen beendet break
standardmäßig nur die innerste Schleife. Mit einem numerischen Argument
kann jedoch angegeben werden, wie viele Schleifenebenen beendet werden
sollen:
<?php
for ($i = 1; $i <= 3; $i++) {
echo "i: $i <br>";
for ($j = 1; $j <= 3; $j++) {
if ($i == 2 && $j == 2) {
break 2; // Beendet sowohl die innere als auch die äußere Schleife
}
echo "j: $j <br>";
}
}
?>Die continue-Anweisung überspringt den Rest des
aktuellen Schleifendurchlaufs und setzt mit dem nächsten Durchlauf
fort:
<?php
for ($i = 1; $i <= 10; $i++) {
if ($i % 2 == 0) {
continue; // Überspringt gerade Zahlen
}
echo $i . " ";
}
// Ausgabe: 1 3 5 7 9
?>Wie bei break kann auch bei continue ein
numerisches Argument angegeben werden, um mehrere Schleifenebenen zu
überspringen:
<?php
for ($i = 1; $i <= 3; $i++) {
for ($j = 1; $j <= 3; $j++) {
if ($j == 2) {
continue 2; // Springt zur nächsten Iteration der äußeren Schleife
}
echo "$i-$j<br>";
}
}
// Ausgabe:
// 1-1
// 2-1
// 3-1
?>Die goto-Anweisung ermöglicht Sprünge im Code zu
benannten Marken:
<?php
$i = 0;
start:
$i++;
echo $i . " ";
if ($i < 5) {
goto start;
}
// Ausgabe: 1 2 3 4 5
?>Hinweis: Die Verwendung von goto wird
generell nicht empfohlen, da es die Lesbarkeit und Wartbarkeit des Codes
beeinträchtigen kann. Es gibt fast immer bessere strukturierte
Alternativen.
Der ternäre Operator bietet eine kompakte Alternative zur
if-else-Anweisung für einfache Zuweisungen:
<?php
$alter = 20;
$status = ($alter >= 18) ? "volljährig" : "minderjährig";
echo $status; // "volljährig"
// Verschachtelte ternäre Operatoren (mit Vorsicht zu verwenden)
$alter = 15;
$status = ($alter < 13) ? "Kind" : (($alter < 18) ? "Teenager" : "Erwachsener");
echo $status; // "Teenager"
?>Der Null Coalescing Operator (??) ist eine kompakte
Alternative zur isset()-Prüfung:
<?php
// Früher:
$username = isset($_GET['user']) ? $_GET['user'] : 'Gast';
// Ab PHP 7:
$username = $_GET['user'] ?? 'Gast';
// Verkettung mehrerer Prüfungen
$username = $_GET['user'] ?? $_POST['user'] ?? $_SESSION['user'] ?? 'Gast';
?>Die Mischung von PHP-Kontrollstrukturen und HTML ist besonders im Web-Kontext üblich:
<!DOCTYPE html>
<html>
<head>
<title>PHP Kontrollstrukturen mit HTML</title>
</head>
<body>
<h1>Benutzerliste</h1>
<?php if (empty($benutzer)): ?>
<p>Keine Benutzer gefunden.</p>
<?php else: ?>
<ul>
<?php foreach ($benutzer as $user): ?>
<li>
<strong><?= htmlspecialchars($user['name']) ?></strong>
<?php if ($user['admin']): ?>
<span>(Administrator)</span>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</body>
</html>Rekursion ist eine Technik, bei der eine Funktion sich selbst aufruft. Dies kann eine elegante Lösung für bestimmte Probleme sein:
<?php
// Berechnung der Fakultät einer Zahl
function fakultaet($n) {
if ($n <= 1) {
return 1;
} else {
return $n * fakultaet($n - 1);
}
}
echo fakultaet(5); // 120 (5 * 4 * 3 * 2 * 1)
// Rekursives Durchlaufen einer verschachtelten Array-Struktur
function arrayDurchlaufen($array, $indent = 0) {
foreach ($array as $schluessel => $wert) {
echo str_repeat("--", $indent) . " $schluessel: ";
if (is_array($wert)) {
echo "<br>";
arrayDurchlaufen($wert, $indent + 1);
} else {
echo "$wert<br>";
}
}
}
$daten = [
"Person" => [
"Name" => "Max Mustermann",
"Kontakt" => [
"Email" => "max@example.com",
"Telefon" => "0123456789"
]
],
"Beruf" => "Entwickler"
];
arrayDurchlaufen($daten);
?>Hinweis: Bei rekursiven Funktionen ist es wichtig,
eine Abbruchbedingung zu definieren, um endlose Rekursionen zu
vermeiden. PHP hat ein Standard-Limit für die Rekursionstiefe, das mit
ini_set('xdebug.max_nesting_level', 200) angepasst werden
kann.
Manchmal ist es sinnvoll, eigene “Kontrollstrukturen” durch Funktionen zu definieren:
<?php
// Wiederholte Ausführung mit bedingtem Abbruch
function retry($callback, $maxVersuche = 3, $pause = 1) {
$versuche = 0;
$ergebnis = null;
$erfolg = false;
while (!$erfolg && $versuche < $maxVersuche) {
$versuche++;
try {
$ergebnis = $callback();
$erfolg = true;
} catch (Exception $e) {
echo "Versuch $versuche fehlgeschlagen: " . $e->getMessage() . "<br>";
if ($versuche < $maxVersuche) {
sleep($pause);
}
}
}
if (!$erfolg) {
throw new Exception("Alle Versuche fehlgeschlagen");
}
return $ergebnis;
}
// Verwendung
try {
$daten = retry(function() {
// Simulierte API-Anfrage
if (rand(0, 1)) {
throw new Exception("Netzwerkfehler");
}
return "Daten erfolgreich abgerufen";
});
echo $daten;
} catch (Exception $e) {
echo "Fehler: " . $e->getMessage();
}
?>Verschachtelung begrenzen: Tief verschachtelte Kontrollstrukturen machen den Code schwer lesbar. Extrahieren Sie komplexe Logik in separate Funktionen.
Alternative Syntax in Templates: Verwenden Sie
die alternative Syntax (if:, endif;,
foreach:, endforeach; usw.) in Templates, um
die Lesbarkeit zu verbessern.
Frühe Rückgabe: Prüfen Sie ungültige Zustände am Anfang einer Funktion und kehren Sie früh zurück, um die Verschachtelungstiefe zu reduzieren.
<?php
// Vermeiden:
function getUserName($userId) {
if ($userId) {
$user = fetchUser($userId);
if ($user) {
return $user->name;
} else {
return null;
}
} else {
return null;
}
}
// Besser:
function getUserName($userId) {
if (!$userId) {
return null;
}
$user = fetchUser($userId);
if (!$user) {
return null;
}
return $user->name;
}
?>Bedingungen extrahieren: Komplexe Bedingungen in Variablen oder Funktionen extrahieren, um die Lesbarkeit zu verbessern.
<?php
// Vermeiden:
if ($user->status === 'active' && $user->email_verified && $user->hasRole('customer') && !$user->isBanned) {
// ...
}
// Besser:
$isEligibleCustomer = $user->status === 'active' &&
$user->email_verified &&
$user->hasRole('customer') &&
!$user->isBanned;
if ($isEligibleCustomer) {
// ...
}
?>Sorgfältiger Umgang mit switch und
goto: Vermeiden Sie Fall-Through-Verhalten bei
switch (vergessene break-Anweisungen) und
verwenden Sie goto nur, wenn es wirklich notwendig
ist.
Rekursionstiefe kontrollieren: Achten Sie bei rekursiven Funktionen auf die maximale Rekursionstiefe und bevorzugen Sie, wenn möglich, iterative Lösungen.