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.

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';
}

?>

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 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.

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.

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 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';
}

?>
Den Themenbereich Kontrollstrukturen vertiefen...


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.