Websiteentwicklung: PHP: Praktische Einführung: Bedingungen
Nun weißt du zwar, wie du auf Benutzereingaben aus GET und POST zugreifen kannst, aber nicht, wie man auf unterschiedliche Eingaben reagiert. Zu diesem Zweck wirst du in diesem Abschnitt eine neue Form der Kontrollstruktur kennen lernen: Die Verzweigungen bzw. Bedingte Anweisungen.
Was ist eine Verzweigung?
[Bearbeiten]Verzweigungen ermöglichen Programmen, Bedingungen zu überprüfen und je nachdem, ob sie erfüllt wurden oder nicht, Anweisungen auszuführen. In gewisser Weise "entscheidet" also das Skript über die weitere Vorgehensweise.
if
[Bearbeiten]Die einfachste Verzweigung in PHP ist die if-Verzweigung:
<?php
if (true) echo 'Hallo Welt!';
?>
Dieses Konstrukt liest sich als: "Wenn die Aussage in der Klammer wahr ist, führe die folgende Anweisung aus." Die Bedingung wird immer auf einen boolschen Wert zurückgeführt, also true oder false ergeben. Da in diesem Beispiel die Aussage immer wahr ist, wird dementsprechend auch die echo-Anweisung stets ausgeführt. Umgekehrt werden wir bei diesem Code
<?php
if (false) echo 'Unsichtbar!';
?>
nie eine Ausgabe sehen.
Mehrere Anweisungen
[Bearbeiten]Es ist auch möglich, mehrere PHP-Anweisungen von der Bedingung abhängig zu machen. Dazu werden diese von geschweiften Klammern umschlossen, wie du das bereits von foreach
kennst:
<?php
if (true) {
echo 'Hallo';
echo ' Welt!';
}
?>
Hinweis |
Anders als in C haben Variablen in PHP innerhalb einer Kontrollstruktur den selben Gültigkeitsbereich wie außerhalb der geschweiften Klammern. |
Operatoren
[Bearbeiten]Die Aussagen innerhalb der Klammern können Operatoren verwenden.
Vergleichsoperatoren
[Bearbeiten]Mit Vergleichsoperatoren können Aussagen über das Verhältnis zweier Werte zueinander getroffen werden:
<?php
$a = 3;
$b = 4;
if ($a < $b) echo $a . ' ist kleiner als ' . $b . '<br />';
if ($a > $b) echo $a . ' ist größer als ' . $b . '<br />';
if ($a == $b) echo $a . ' ist gleich ' . $b . '<br />';
if ($a != $b) echo $a . ' ist ungleich ' . $b . '<br />';
?>
Als Ausgabe erhältst du:
3 ist kleiner als 4 3 ist ungleich 4
Jetzt siehst du auch, warum es wichtig ist, das einfache Gleichheitszeichen in PHP stets als Zuweisung zu sehen. Würden wir nämlich
<?php
$a = 3;
$b = 4;
if ($a = $b) echo $a . ' ist gleich ' . $b;
?>
schreiben, ergäbe die Ausgabe
4 ist gleich 4
Mit $a = $b
wird $a
der Wert von $b
zugewiesen, und das Ergebnis dieser Zuweisung, also 4, als Bedingung verwendet. Nach den Umwandlungsregeln für den Typ Boolean sind Integer außer 0 immer true, somit auch die Bedingung.
Für Gleich und Ungleich existiert noch eine typensichere Variante mit je einem Gleichheitszeichen mehr: ===
und !==
. Aussagen gelten dann als wahr, wenn die Werte links und rechts vom Operator absolut gleich (ungleich) sind, sowohl vom Wert, als auch vom Typ:
<?php
if (5 == '5') echo 'Ich bin wahr';
if (5 === '5') echo 'Ich nicht';
?>
Eine vollständige Liste der Vergleichsoperatoren findest du im ausführlichen Kapitel Operatoren.
Logische Operatoren
[Bearbeiten]Die zweite Gruppe der Operatoren, die speziell für Verzweigungen existieren, sind die logischen Operatoren. Der einfachste davon ist "Nicht" (!
). "Nicht" kehrt eine Aussage ins Gegenteil:
<?php
if (!true) echo 'Ich bin Unsichtbar!';
?>
true wurde hier zu false, somit ist die gesamte Bedingung unwahr. Ein etwas komplexeres Beispiel:
<?php
if (!(5 <= 4)) echo 'Mich sieht man';
?>
Von solchen Konstruktionen ist aber abzuraten. Das Beispiel lässt sich leicht auf (5 > 4)
umschreiben.
Um Aussagen logisch zu verknüpfen, verwendet man die Operatoren "Und" (&&
), "Oder" (||
) und "Exklusives Oder" (xor
):
<?php
if (4 > 3 && 'text' == 'text') echo 'Damit ich zu sehen bin, muss sowohl 4 größer als 3, als auch die beiden Strings übereinstimmen.';
if (true || false) echo 'Hier muss wenigstens eine Bedingung wahr sein. Da das der Fall ist, bin ich zu sehen.';
if (true xor true) echo 'Bei xor muss exakt eine der Bedingungen wahr sein (nicht beide oder keine). Deshalb bin ich unsichtbar.';
?>
Auch diese lassen sich zu komplexeren Bedingungen zusammenfügen:
<?php
if ((4 > 3 && false) || (1 != 1 || true)) echo 'Hallo Welt!';
?>
"Hallo Welt" wird ausgegeben, da
(4 > 3 && false) || (1 != 1 || true)
ausgewertet wird zu
(false) || (true)
else und elseif
[Bearbeiten]Mit else
kannst du Anweisungen festlegen, die nur ausgeführt werden, wenn die Bedingung nicht zutrifft:
<?php
// Entferne die Kommentarmarkierung einer der folgenden beiden Zeilen zum Testen:
// $a = true;
// $a = false;
if ($a) {
echo '$a ist wahr';
} else {
echo '$a ist unwahr';
}
?>
Außerdem lässt sich mit elseif
auch für diesen Fall eine weitere Bedingung stellen:
<?php
if ($a < $b) {
echo '$a ist kleiner $b';
} elseif ($a == $b) {
echo '$a ist gleich $b';
} else {
echo '$a ist größer $b';
}
?>
switch
[Bearbeiten]Wenn eine Variable auf viele verschiedene Aussagen hin überprüft werden soll, wird die Sache mit if schnell unübersichtlich. Der folgende Code gibt das Zahlwort einer eingegebene Ganzzahl von 1 bis 5 aus:
<?php
$number = (int)$_GET['number'];
echo "Die Zahl $number heißt ausgeschrieben: ";
if ($number == 1) {
echo 'Eins';
} elseif ($number == 2) {
echo 'Zwei';
} elseif ($number == 3) {
echo 'Drei';
} elseif ($number == 4) {
echo 'Vier';
} elseif ($number == 5) {
echo 'Fünf';
} else {
echo 'Ungültige Zahl!';
}
?>
In dieser if-Abfrage wird ein und dieselbe Variable mit zahlreichen Werten verglichen. Für diese Aufgabe gibt es eine spezielle Kontrollstruktur: switch.
$number = (int)$_GET['number'];
echo "Die Zahl $number heißt ausgeschrieben: ";
switch ($number) {
case 1:
echo 'Eins';
break;
case 2:
echo 'Zwei';
break;
case 3:
echo 'Drei';
break;
case 4:
echo 'Vier';
break;
case 5:
echo 'Fünf';
break;
default:
echo 'Ungültige Zahl!';
}
Sehen wir uns die einzelnen Bestandteile der Anweisung einmal genauer an.
switch
[Bearbeiten]switch leitet die Kontrollstruktur ein. In der Klammer kann ein beliebiger Wert stehen, z.B. eine Variable, eine Konstante oder der Rückgabewert einer Funktion; Vergleichs- und logische Operatoren jedoch nicht.
case
[Bearbeiten]Mit case wird der zu vergleichende Wert festgelegt. switch vergleicht immer typenschwach, als ob du eine if-Abfrage mit dem Operator ==
geschrieben hättest. Alle Anweisungen nach case werden ausgeführt, sie müssen, anders als bei if, nicht in geschweifte Klammern gesetzt werden.
Es ist auch möglich, mehreren Fälle die gleichen Anweisungen zuzuordnen:
<?php
switch ($number) {
case 2:
case 3:
case 5:
echo 'Die Zahl ist eine Primzahl.';
break;
case 1:
case 4:
echo 'Die Zahl ist keine Primzahl.';
break;
default:
echo 'Ungültiger Wert';
}
?>
Dieses Beispiel funktioniert wie eine Oder-Verknüpfung (||
) der Fälle.
break
[Bearbeiten]Nach dem Anweisungsblock solltest du das Schlüsselwort break setzen. Es bewirkt in den Anweisungsblöcken aller Kontrollstrukturen (also auch z.B. in if oder foreach) einen "Ausbruch" aus der gesamten Struktur. Betrachten wir, was ohne break geschehen würde:
<?php
// obiges Beispiel ohne break
switch ($number) {
case 2:
case 3:
case 5:
echo 'Die Zahl ist eine Primzahl.';
case 1:
case 4:
echo 'Die Zahl ist keine Primzahl.';
default:
echo 'Ungültiger Wert';
}
?>
Bei $number = 10
ist noch alles in Ordnung:
Ungültiger Wert
Mit $number = 5
zeigt sich allerdings das Problem:
Die Zahl ist eine Primzahl.Die Zahl ist keine Primzahl.Ungültiger Wert
Wie bereits beschrieben: Alle Anweisungen nach case werden ausgeführt. Da kein break erfolgt, geschieht dies mit allen drei echos.
default
[Bearbeiten]default ist gewissermaßen das else aus dem Ursprungsbeispiel. default ist optional und immer wahr (wie der Ausdruck $number == $number
).
Trinitätsoperator
[Bearbeiten]Der Trinitätsoperator (engl. "ternary operator", weswegen auch oft als Ternäroperator bezeichnet) gehört nicht zu den Kontrollstrukturen, sondern zu den Vergleichsoperatoren und findet vor allem bei Zuweisungen Verwendung.
Beispiel
[Bearbeiten]Auf der höchsten error_reporting-Stufe wird dir ein E_NOTICE-Fehler angezeigt, wenn du auf eine nicht vorhandene Variable zugreifen möchtest. Dieser Hinweis ist hilfreich, da so Tippfehler schneller gefunden werden können. Allerdings kommt es gerade bei Benutzereingaben häufiger vor, dass der Wert (respektive Schlüssel im Array) nicht gesetzt worden ist.
Nehmen wir einmal an, alle Seiten unseres Beispielprojekts sollen über eine einzige Datei index.php laufen, sodass wir Dinge wie die Herstellung der Datenbankverbindung zentral an einer Stelle verarbeiten können. Die gewünschte Unterseite kommt mittels $_GET-Parameter "page". Wenn jetzt allerdings jemand unsere Seite www.example.com
aufruft, existiert dieser Schlüssel nicht. Hier kommt der Trinitätsoperator ins Spiel:
<?php
$page = (isset($_GET['page'])) ? $_GET['page'] : 'index';
?>
Der Variable $page
wird das Ergebnis dieses Ausdrucks zugewiesen: Wenn der Schlüssel 'page' in $_GET existiert, entspricht dies dem Wert, ansonsten wird 'index' zugewiesen. Das entspricht:
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = 'index';
}
?>
Praktische Anwendung
[Bearbeiten]Genau das letzte Beispiel wollen wir in die Tat umsetzen: Unsere fiktive Website soll ausschließlich über eine zentrale index.php gesteuert werden, die einzelnen Inhalte finden sich in Templates wieder. Aus den im Kapitel Benutzereingaben und Sicherheit vorgestellten Gründen ist dringend davon abzuraten, den Wert von 'page' direkt ins Dateisystem, etwa in der Form include $page . 'tpl.php'
zu übersetzen. Stattdessen definieren wir eine Liste an gültigen Seiten.
<?php
/* Vorbelegung der Variable $page */
$page = !empty($_GET['page']) ? trim($_GET['page']) : 'index';
/* erlaubte Seiten */
$pages = array('index', 'review', 'impressum');
/* wenn die angeforderte Seite nicht im Array aufgelistet ist, wird die Seite 404 aufgerufen */
if(!in_array($page, $pages)) {
$page = '404';
}
/* Möglicherweise gibt es noch weitere Logik für diese Seite */
$logic = 'logic/' . $page . '.php';
if (file_exists($logic))
{
include($logic);
}
/* Ansicht einbinden */
include('templates/header.tpl.php');
include('templates/' . $page . '.tpl.php');
include('templates/footer.tpl.php');
?>
Ausblick
[Bearbeiten]Soeben hast du die Urform eines Front-Controllers kennengelernt. Dieser nimmt Anfragen entgegen, führt die auf jeder Seite nötigen Schritte aus und leitet die Aufgaben an Untercontroller weiter.
Später wird eine Datenbank für uns die Templates bereitstellen, zusammen mit der Information, ob weitere Logik vorhanden ist.