Es ist bei Stringvergleichen gar nicht so selten zu finden, statt strcmp zu benutzen dies mit einem einfachen Vergleich (==) zu erledigen,
also statt
einfach
zu schreiben.
Klappt auch in den meisten Fällen, aber leider nicht immer. Weniger bekannt ist:
PHP prüft den vor den einfachen (typeschwachen) Vergleich beide Stringinhalte, ob diese einen numerischen Inhalt haben.
Sind beide Stringinhalte numerisch, wird auch ein numerischer Vergleich durchgeführt.
So auch wenn eine Seite ein numerischer Datentyp ist, was allgemein bekannt ist.
Beispiele typeschwacher Stringvergleiche
Wie die Beispiele zeigen, werden auch Hexadezimalausdrücke als numerisch angesehen und führende Steuerzeichen werden auch großzügig ignoriert.
Eine führende 0 führt dagegen nicht zu einer Interpretation als Oktalzahl.
Diese Stolperfallen lauern versteckt auch in anderen Konstrukten, wie z.B. switch oder usort.
Dazu die folgenden Beispiele.
Beispiel switch
Hier wird numerisch verglichen, daher tritt Fall 1 ein, obwohl '7e0' !== '07' ist.
Im PHP-Manual zu switch ist zwar der Hinweis zu lesen daß switch typeschwache Vergleiche durchführt, ignoriert aber die Probleme durch "Beispiel #2 switch gestattet den Vergleich mit Strings".
Die folgende switch-Variante nutzt den strengen Vergleich, ist aber schlecht lesbar:
Ich persönlich nutze switch nur ungerne und lieber if/elseif/else Konstrukte.
Beispiel usort
Das Beispiel zeigt deutlich, daß usort bei Verwendung der Vergleichsfunktion cmp mit dem typschwachen Vergleich nicht das gewünschte Resultat bringt.
sort und usort mit cmpStr, welche strcmp benutzt, arbeiten richtig.
Fazit:
Für den sicheren Stringvergleich auf Gleich/Ungleich kann nur der strenge Vergleich (===/!==) empfohlen werden.
Wird in den obigen ersten Beispielcode konsequent === benutzt, bleibt die Ausgabe leer.
Für einen größer/kleiner Vergleich von Strings bleibt nur strcmp zu nehmen.
LG jspit
PS: Mich hat dies mal viel Zeit bei einer Fehlersuche gekostet, vielleicht erspart dieser Beitrag dies dem Einen oder Anderen.
also statt
PHP-Code:
$product = 'Milch';
if(strcmp($product,"Milch") == 0)..
PHP-Code:
if($product == "Milch")..
Klappt auch in den meisten Fällen, aber leider nicht immer. Weniger bekannt ist:
PHP prüft den vor den einfachen (typeschwachen) Vergleich beide Stringinhalte, ob diese einen numerischen Inhalt haben.
Sind beide Stringinhalte numerisch, wird auch ein numerischer Vergleich durchgeführt.
So auch wenn eine Seite ein numerischer Datentyp ist, was allgemein bekannt ist.
Beispiele typeschwacher Stringvergleiche
PHP-Code:
$myString = '01200';
if($myString == '0001200') echo "'0001200':true ,";
if($myString == '12e2') echo "'12e2':true ,";
if($myString == '0x4b0') echo "'0x4b0':true ,";
if($myString == ("\r\n\t ".'1200')) echo "'CRLF 1200':true ,";
if($myString == '1200.0000000000000000028') echo "'1200.0000000000000000028':true ,"; //32Bit System
//Ausgabe
//'0001200':true ,'12e2':true ,'0x4b0':true ,'CRLF 1200':true ,'1200.0000000000000000028':true ,
Eine führende 0 führt dagegen nicht zu einer Interpretation als Oktalzahl.
Diese Stolperfallen lauern versteckt auch in anderen Konstrukten, wie z.B. switch oder usort.
Dazu die folgenden Beispiele.
Beispiel switch
PHP-Code:
$selector = '07';
switch ($selector) {
case '7e0' : echo 'Fall 1';
break;
case '07': echo 'Fall 2';
break;
}
//Ausgabe: Fall 1
Im PHP-Manual zu switch ist zwar der Hinweis zu lesen daß switch typeschwache Vergleiche durchführt, ignoriert aber die Probleme durch "Beispiel #2 switch gestattet den Vergleich mit Strings".
Die folgende switch-Variante nutzt den strengen Vergleich, ist aber schlecht lesbar:
PHP-Code:
$selector = '07';
switch (true) {
case $selector==='7e0' : echo 'Fall 1';
break;
case $selector==='07': echo 'Fall 2';
break;
}
//Ausgabe: Fall 2
Beispiel usort
PHP-Code:
function cmp($a, $b)
{//ungeeignet für strings
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
function cmpStr($a, $b)
{
return strcmp($a, $b);
}
$a1 = $a2 = $a3 = array('0xa','0x1','011','0af',);
sort($a1, SORT_STRING);
var_dump($a1);
echo "<br>";
usort($a2, "cmpStr");
var_dump($a2);
echo "<br>";
usort($a3, "cmp");
var_dump($a3);
/*
Ausgabe:
array(4) { [0]=> string(3) "011" [1]=> string(3) "0af" [2]=> string(3) "0x1" [3]=> string(3) "0xa" }
array(4) { [0]=> string(3) "011" [1]=> string(3) "0af" [2]=> string(3) "0x1" [3]=> string(3) "0xa" }
array(4) { [0]=> string(3) "0af" [1]=> string(3) "0x1" [2]=> string(3) "0xa" [3]=> string(3) "011" }
*/
sort und usort mit cmpStr, welche strcmp benutzt, arbeiten richtig.
Fazit:
Für den sicheren Stringvergleich auf Gleich/Ungleich kann nur der strenge Vergleich (===/!==) empfohlen werden.
Wird in den obigen ersten Beispielcode konsequent === benutzt, bleibt die Ausgabe leer.
Für einen größer/kleiner Vergleich von Strings bleibt nur strcmp zu nehmen.
LG jspit
PS: Mich hat dies mal viel Zeit bei einer Fehlersuche gekostet, vielleicht erspart dieser Beitrag dies dem Einen oder Anderen.
Kommentar