In PHP – wie natürlich auch in anderen Programmiersprachen – gibt es verkürzte truthy-Prüfungen. Ob, wie und wann man sie einsetzt muss aber genau überlegt sein. Das hilft am Ende nicht nur der Lesbarkeit sondern vermeidet auch Bugs, die auf Grund falsch gedachter oder vermeintlich logischer Prüfungen aufkommen.
Was ist eine truthy-Prüfung
In kurz gesagt geht es bei einer truthy-Prüfung darum schnell zu evaluieren, ob eine Variable wahr ergibt. Das ist i.d.R. keine echte inhaltliche Prüfung sondern vielmehr die Frage „existiert die Variable“ und „hat sie irgendeinen Inhalt“. Wobei das mit dem Inhalt so eine Sache ist…
Gibt es sie wirklich?
Das ist die erste Frage. Das ist in PHP nicht so unwahrscheinlich schwer weil im normalen Betrieb gehört PHP zu den schwachtypisierten Sprachen. Im Gegensatz zu starken Typisierungen muss ich also eine Variable nicht erst grundlegend initialisieren und auch nicht sagen, welchen Werttyp sie haben kann bzw. soll. Aber natürlich existiert eine Variable auch nur dann, wenn ich sie irgendwann einmal benutzt habe. Habe ich das – egal in welche Form – existiert sie.
Und hat sie einen Inhalt?
Das ist schon eine spannendere Frage. Jeder wird zustimmen das Dinge wie eine Zahl (darunter auch die 0 – nicht zu verwechseln mit dem informationstechnischen NULL) oder eine Zeichenkette (gern auch gemischt also z.B. auch „abc123“) ein valider Inhalt sein kann. Und wie steht’s mit einer leeren Zeichenkette? Als Beispiel:
$variable = "";
Wäre das auch eine Variable die auf wahr auswerten würde? Tatsächlich verhält sich PHP hier „intelligent“ und erkennt, dass die Variable nicht befüllt ist.
Vorsicht ist aber geboten, wenn es sich um Variablen aus einem Formular handelt und diese ggf. auch noch mit Frameworks und Co „behandelt“ werden. Hier kann ein $_POST[„variable“] auch wenn sie tatsächlich auch leer gelassen wurde trotzdem auf „wahr“ auswerten.
Noch wesentlich beeindruckender ist es, wenn eine Variable ein Klassenobjekt enthält:
$variable= new StdClass();
if ($variable)
echo "ja";
In diesem Beispiel wird auch „ja“ ausgegeben – auch wenn man ja nichts weiter gemacht hat als ein „leeres“ Objekt initialisiert.
Schwache Typisierung als „Falle“
Das Problem: Wenn ich in einem Script stecke, welches vielleicht als Unterprogramm zu einem anderen Script läuft weiß ich mitunter nicht, womit die Variable mal eingerichtet wurde. Es kann also sein, dass ich auf „wahr“ prüfe und trotzdem keine „gute“ Antwort bekomme.
Lösungen
Generell empfiehlt sich natürich immer
declare(strict_types=1);
zu setzen. Warum? Naja es ist kein Allheilmittel aber es zwingt PHP schon mal dazu stärker zu typisieren. Das heißt, es ist nicht mehr so ohne Weiteres möglich zwischen verschiedenen Typen innerhalb einer Variable hin und her zu springen.
Auch das Verwenden von Funktionen und Klassen hilft. Hat eine Variable nicht den passenden Wert steigt bereits die Funktion entsprechend aus.
Das alles hilft aber tatsächlich nicht gegen das oben genannte Problem – es schafft nur klare Voraussetzungen dafür, dass man dann eine „vernünftige“ Prüfung macht – aus der man dann gleich noch mehr ableiten kann.
Was ist eine „vernünftige“ Prüfung?
An dieser Stelle möchte ich mit einer Analogie starten, dass macht die Sache vielleicht greifbarer. Stellen wir uns vor wir sind Kassierer an einer Kasse und wollen vom Kunden 10 Euro für seinen Einkauf haben (in dem Beispiel gehen wir mal davon aus das der Einkauf exakt 10 Euro kostet – ich weiß, in der Realität ist das nicht so oft der Fall ;)). Der Kunde reicht uns etwas herüber.
In dem oben beschriebenen Fall würden wir uns einfach nur Fragen „Hat der Kunde was rübergereicht“ – und das ganze mit „ja“ beantworten. Fertig. Keine Prüfung darauf was es ist – vielleicht hat er uns nur seine Einkaufsliste gegeben, vielleicht noch ein zu verrechnender Pfandbon oder vielleicht auch einfach ein abgelaufenes Parkticket – alles möglich. Wir wissen es schlicht nicht und bei der „einfachen“ Prüfung fragen wir auch nicht weiter nach. Wir sind fertig mit der Welt und ob am Ende unsere Kasse stimmt – who cares!
Eine vernünftige Prüfung würde im Kassenfall doch so aussehen: Hat der Kunde etwas rübergereicht? -> Ja. Und ist das mindestens ein 10 Euro-Schein? Wenn hier jetzt ein nein raus kommt müssen wir irgendwie anders reagieren, oder?
Genauso sollte man auch bei Programmen (und im konkreten Fall bei PHP) vorgehen. Man prüft nicht nur, ob die Variable irgendwie da ist, sondern validiert bestmöglich auf den Inhalt. Hier ein paar Beispiele die sicher nicht für jeden Anwendungsfall und für jedes Problem sauber funktionieren aber eine Idee liefern, was man so machen kann:
//prüfen ob eine Variable eine Zahl ist
if ((int)$variable === $variable)
//oder auch möglich
if (is_int($variable))
//prüfen auf Zeichenkette
if (strlen($variable)>0)
//oder auch z.B. als regex
if (preg_match('/([A-z0-9])*/',$variable))
//prüfen auf arrays - etwas tricky
if (is_array($variable))
//oder z.b. auch über die Anzahl -
//hier aber besser mit is_Array kombinieren -> sonst Fehler
//falls kein Array
if (is_array($variable) && count($variable) > 0)
Natürlich kann man noch weit restriktiver prüfen aber ich denke das gibt einen guten Ansatz, wie so etwas praktisch mit „einfachen“ Mitteln schon mal mehr Sicherheit gibt.
Ich selbst tendiere immer stärker zu einem Zero-Trust-Ansatz, d.h. wann immer sinnvoll und nötig prüfe ich meine Variablen gegen und verwende OOP um schon beim „betreten“ des Codes sicher zu sein, dass meine Variablen gewisse Typen haben. strict-types ist in meinen Codes inzwischen eigentlich auch immer gesetzt. Wer übrigens einfach mal bisschen „rumspielen“ will und selbst schauen möchte, wie sich verschiedene PHP Versionen in verschiedenen Situationen verhalten, dem seien Tools wie https://onlinephp.io/ gern empfohlen.
Letztendlich sind truthy Prüfungen weit verbreitet und scheinen bequem. Und es gibt mit Sicherheit auch einige kleine Anwendungsbereiche in denen es „mal eben schnell“ ausreicht. Gute Programmierung sollte ich aber darauf niemals grundlegend verlassen.
Kommentar verfassen