PHP: Das if des grauens
Heute habe ich ein kleines Problem mit PHP gehabt. Natürlich ist dieses oder ein ähnliches Problem lange bekannt. Es ist auch kein wirklicher Bug von PHP sondern einfach das richtige Verhalten bei diesen Fällen aufgrund von dem Designe von PHP. Aber ich habe mir gedacht, dass es seien kann, dass der ein oder andere vielleicht auch dieses Problem hat/haben könnte.
Vielleicht erinenert er sich dann früher oder später an diesen Beitrag oder findet ihn via google und ich helfe indirekt.
Mein Problem
Heute hatte ich auf der Arbeit folgendes Problem:
In einem 2D Array stehen alle Auftragspositionen eines Tages mit zugehöriger Auftragsnummer. Es sollen alle Auftragspositionen ausgegeben werde. Jeder Auftrag soll klar gekennzeichnet sein. Ganz einfach: Schleife über das Array, Auftragsnummer des letzten Durchlaufs merken und wenn die Auftragsnummer des letzten Durchlaufs ungleich der Auftragsnummer in diesem Durchlauf ist, dann muss ich die Markierung einfügen, dass hier ein neuer Auftrag beginnt.
Aufbau Auftragsnummer: A[LAUFENDE NUMMER] (also ein String)
Aber: Vor dem allerersten Auftrag fehlte diese Markierung.
Der Grund
In der Variable $merker merke ich mir die Auftragsnummer des vorherigen Durchlaufs. Damit es bei der ersten Entscheidung nicht crached setzte ich $merker zuvor auf 0. Mein Gedankengang: Merker ist entwerder Intetger (int) mit dem Wert 0 oder false. Ein String ist immer true (alles außer 0 ist true).
Mein Code
Mein Code sah wie folgt aus
$merker = 0;
//Hier etwas code und dann in der schleife:
if($merker != $auftragsnummer['auftrag'])
{
echo $auftragsnummer['auftrag'];
$merker = $auftragsnummer['auftrag'];
}
//sonstige ausgaben und ende der Schleife
Was ich nicht verstanden habe
Wenn $auftag[‚auftragsnummer‘] irgend ein String ist, dann muss das IF zwangsläufig true sein (weil true != false und irgendeinstring != int(0)
Die Lösung
Nach langer Suche haben wir die Lösung gefunden:
Wenn ein String mit einem Int verglichen werden soll versucht PHP aus dem String ein Integer zu machen. PHP verhält sich dabei wie die Funktion intval().
Achtung hier liegen die Stolpersteine
Die Funktion intval() versucht aus dem Eingabewert irgendwie einen Integer-Wert zu bauen. Das führt manchmal zu sehr merkwürdigen Ergebnissen: intval(1) => int(1) //Logisch int bleibt int
intval(1.4) => int(1) //Logisch float wird zu int
intval("0") => int(0) //String "0" wird zu int mit Wert 0
intval("A") => int(0) //String "A" wird zu int mit Wert 0
intval("12ABC") => int(12) //String "12ABC" wird zu int Wert 12, da der String mit den Ziffern 12 beginnt
intval("ABC12") => int(0)
Hintergrund
In (fast) jeder Programmiersprache gilt „a == b“ vergleicht a mit b. Wenn der Inhalt gleich ist, dann ist der Ausdruck wahr, ansonsten ist er falsch. PHP kennt keine festen Datentypen. Sprich eine Zahl kann zu einer Zeichenkette (string) werden und umgekehrt. Daher kennt PHP auch den Operator ===. Dabei wird nicht nur der Inhalt, sondern auch der Typ verglichen.
Bsp:
(5 == 5) => true
(5 == "5") => true (int 5 ist string 5)
(5 ==== "5") => false (int 5 ist ungleich string 5 da unterschiedliche Typen)
Meine Lehre
Ich habe gelernt, dass der === Operator wichtiger ist als ich angenommen habe. Ja ich benutze ihn selten, aus dem einfachen Grund: Er wird meistens einfach nicht benötigt. Meistens sind die Datentypen auf beiden Seiten eh gleich, oder es interessiert mich nicht, welchen Datentyp PHP der Variable gegeben hat, da es für mich eh nur auf den Inhalt ankommt.
Das ganze kann aber sehr böse bei einem if($a == $b) enden, wenn die Variablen sonst wie gefüllt werde.
Beispiel:
//Normalfall: $a = "ABC";
In $a ist meistens ein String, aber in diesem einen Fall steht einfach nur eine 5 drin -> PHP sagt $a ist Int.
$b = "DEF";
if($a == $b) => string("ABC") ist nicht string("DEF") -> false
//a ist nun blöderweise 5 (und damit int). Aber alles ist ok
$a = 5;
$b = "DEF";
if($a == $b) => int(5) ist nicht [string("DEF") umwandlung in] int(0) -> false
//a ist leider wieder 5 (und damit int), b ist ein String der dummerweise mit 5 beginnt
$a = 5;
$b = "5dsarew4";
if($a == $b) => int(5) ist [string("5dsarew4" umwandlung in] int(5) -> true
if($a === $b) => int ist ungleich string -> false
In $b steht eine String, z.b. „5a“. Da PHP nun aber das „a“ bei dem vergleichen durch intval entfernt bleibt ein if(5 == 5) übrig und damit ist es true.