Abschnitt 7 · Lektion 1
Die drei Sorten Fehler
PHP kennt drei Sorten von Problemen, und sie unterscheiden sich nicht darin, wie schlimm sie sind. Sie unterscheiden sich darin, was danach passiert.
Eine Warnung ist die gefährlichste
<?php
$noten = ["mia" => 5, "ben" => 4, "tom" => 5, "ida" => 4];
// In der Liste steht "Tom" gross, im Array klein.
$klasse = ["mia", "ben", "Tom", "ida"];
$summe = 0;
foreach ($klasse as $name) {
$summe += $noten[$name];
}
echo "Summe: ", $summe, "\n";
echo "Durchschnitt: ", number_format($summe / count($klasse), 1, ",", "."), "\n";
echo "Das Programm ist bis hier gekommen.\n"; Eine Warning hält nichts auf. Das Programm rechnet weiter, kommt bis zum Ende und meldet sich mit
Exit-Code 0 zurück, also mit demselben Code wie ein völlig sauberer Lauf. Sehen kannst du die Zahl
wie in Lektion 1.4 im Terminal: php index.php; echo $? schreibt sie als letzte Zeile hin, und hier
ist es eine 0, trotz der Warnung darüber.
Sieh dir an, was dabei herauskommt. In der Liste steht "Tom" groß geschrieben, im Array liegt der
Wert unter "tom". PHP findet den Schlüssel nicht, meldet Undefined array key "Tom" auf dem
Fehlerkanal und liefert für diese Stelle null. Und null ist beim Addieren eine Null. Die Summe
ist 13 statt 18, der Durchschnitt 3,3 statt 4,5, und die letzte Zeile behauptet fröhlich, alles sei
gut gegangen.
Das ist der Grund, warum eine Warnung teurer ist als ein Absturz. Ein Absturz fällt sofort auf. Eine falsche Zahl fällt auf, wenn sich jemand beschwert, und bis dahin steht sie in Rechnungen und Berichten. Behandle jede Warnung wie einen Fehler. In diesem Kurs prüft fast jede Aufgabe, dass auf dem Fehlerkanal nichts steht, und genau deshalb.
Ein Error bricht ab
<?php
echo "Vor der Rechnung\n";
$teiler = 0;
echo intdiv(100, $teiler), "\n";
echo "Diese Zeile wird nie ausgegeben.\n"; Ein Error beendet das Programm sofort. Die erste Zeile wird noch ausgegeben, die letzte nicht
mehr. Auf dem Fehlerkanal steht Uncaught DivisionByZeroError: Division by zero, und der Exit-Code
ist 255 statt 0. Dasselbe php index.php; echo $? im Terminal endet hier mit einer 255.
Typische Fälle sind eine Division durch null, ein Aufruf einer Funktion, die es nicht gibt, oder ein Wert vom falschen Typ an einem Parameter mit Typangabe. Der Parse-Fehler aus Lektion 1.4 gehört ebenfalls in diese Familie, nur passiert er noch früher: dort startet die Datei gar nicht erst.
Gute Nachricht am Rande: PHP 8 hat viele Fälle, die früher nur eine Warnung waren, zu Fehlern gemacht. Die Division durch null ist einer davon. Vorher lief so ein Programm weiter und lieferte Unsinn, heute hört es auf.
Eine Ausnahme lässt sich fangen
<?php
echo "Vor der Rechnung\n";
$teiler = 0;
try {
echo intdiv(100, $teiler), "\n";
} catch (DivisionByZeroError $fehler) {
echo "Gefangen: ", $fehler->getMessage(), "\n";
}
echo "Und hier laeuft das Programm weiter.\n"; Und jetzt der Unterschied, um den es im Rest des Abschnitts geht. Dieselbe Zeile, dasselbe Problem,
nur steht sie diesmal in einem try-Block. Das Ergebnis: kein Abbruch, Exit-Code 0 (auch das
kannst du mit echo $? nachsehen), und der Fehlerkanal bleibt leer. Du hast die Meldung abgefangen und selbst entschieden, was passieren soll.
Eine Exception ist ein Fehler, den jemand absichtlich wirft, damit ihn jemand anderes auffangen
kann. Sie bricht das Programm nur dann ab, wenn niemand sie auffängt. Streng genommen sind Error
und Exception in PHP zwei Geschwister unter einem gemeinsamen Dach namens Throwable, und beide
lassen sich fangen. Wie das im Einzelnen geht, steht in Lektion 7.2.
Fangen heißt aber nicht wegmachen. Wenn du eine Ausnahme abfängst, übernimmst du die Verantwortung
für das, was danach kommt. Ein catch-Block, der nichts tut, ist deshalb schlimmer als gar keiner.
Ein Weg, den du kennen solltest, um ihn nicht zu gehen
<?php
$posten = ["Kaffee" => 250];
// Ohne @ meldet PHP den fehlenden Schluessel auf dem Fehlerkanal.
$menge = $posten["Tee"];
var_dump($menge);
// Mit @ ist dieselbe Zeile still.
$still = @$posten["Tee"];
var_dump($still);
echo "In beiden Variablen steht dasselbe: nichts.\n"; Ein @ vor einem Ausdruck unterdrückt jede Meldung, die dieser Ausdruck erzeugt. Der Fehlerkanal
bleibt leer, alles sieht sauber aus.
Sieh dir trotzdem die beiden var_dump() an: Beide sagen NULL. An der Sache hat sich nichts
geändert, nur die Meldung ist weg. Du wirst das @ in fremdem Code sehen, meistens vor
Dateizugriffen, und es ist fast immer eine Stelle, an der jemand ein Problem nicht lösen wollte.
Der ehrliche Weg ist der aus 7.2: hinsehen, abfangen, entscheiden.
Zum Mitnehmen
In Lektion 1.4 hast du Fehlermeldungen gelesen. Jetzt bekommen sie Namen, und der Unterschied zwischen ihnen ist der Stoff für den ganzen Abschnitt: Eine Sorte bricht ab, eine läuft weiter, und eine dritte lässt sich abfangen. Nur bei der letzten hast du eine Wahl.
Jetzt du
Basis Konto, kostenlosZu 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.