PHP Warum truthy Prüfungen nicht immer wahr sind

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.

  • WordPress Plugins II: Ich klick mir die Welt

    WordPress (und auch andere CMS) sind verlockend: Schnell installiert, schnell mit Plugins erweitert und schnell online im Netz. Es ist aber leider etwas mehr als ein Pippi Langstrumpf Abenteuer bei dem 3×3 = 6 ergibt…

  • WordPress Performance: Warum zu viele Plugins deine Seite ausbremsen

    WordPress erfreut sich seit Jahren großer Beliebtheit – trotz oder vielleicht gerade wegen seines Alters. Heute wird damit fast alles gebaut: vom persönlichen Blog über Vereinsseiten bis hin zu ausgewachsenen Shopsystemen. Ursprünglich war WordPress aber eine reine Blogsoftware. Viele WordPress‑Seiten werden langsam, weil zu viele Plugins geladen werden – oft ohne dass Betreiber es merken.…

  • HTTP 500: Fehler – nur welcher?

    Neulich haben wir schon über den Unterschied zwischen 401 und 403 gesprochen. Jetzt wollen wir weiterschauen: der HTTP Code 500 ist ein weiterer häufiger Kandidat – und verhält sich „mysteriös“. Teilweise ist das aber auch gut so.

  • PHPUnit-Tests: Wenn ein roter Test ein Erfolg ist

    Ein roter PHPUnit‑Test bedeutet nicht automatisch, dass etwas kaputt ist. Manchmal zeigt er sogar, dass alles genau so funktioniert, wie es soll – zum Beispiel, wenn eine neue Auth‑Schicht greift. Ein kleiner Einblick in unsere modulare Vorgehensweise und warum ‚rot‘ nicht immer schlecht ist.

  • Neues Kind in der eproi-Familie: Aeventus.de – für clevere Events

    Bisher stand eproi für maßgeschneiderte WordPress-Plugins und technisch raffinierte Programmierungen. Mit Aeventus präsentieren wir erstmals ein eigenständiges Softwareprodukt – browserbasiert, geräteunabhängig und bereit für den öffentlichen Auftritt.

Kommentare

Kommentar verfassen