The below returns false
on PHP 7 but true
on PHP 8. Could someone explain why this is happening?
var_dump("U0M262" > 100000);
There is no obviously correct result for a comparison between a string and a number. In many languages, it would just give an error; in others, including PHP, the language tries to make sense of it by converting both operands to the same type, but this involves a judgement of which type to "prefer".
Historically, PHP has preferred comparing numbers to comparing strings: it treated "U0M262" > 100000
as (int)"U0M262" > 100000
. Since (int)"U0M262"
has no obvious value, it is evaluated as 0
, and the expression becomes 0 > 100000
, which is false.
As of PHP 8, this behaviour has changed and PHP now only uses a numeric comparison for "numeric strings", e.g. "42"
clearly "looks like" 42
.
Since "U0M262"
doesn't fit the requirements for a numeric string, "U0M262" > 100000
is now treated as "U0M262" > (string)100000
. This does a byte-wise comparison of the sort order for the two strings, and finds that since "U" comes after "1" in ASCII (and any ASCII-derived encoding, including UTF-8), the result is true.
Because of how ASCII (and compatible encodings such as UTF-8) is arranged:
As ever, you can tell PHP which comparison you intended, and get the correct behaviour in all versions, using explicit casts:
var_dump((int)"U0M262" > (int)100000); // bool(false)
var_dump((string)"U0M262" > (string)100000); // bool(true)
(Obviously, this makes no sense if you're hard-coding both sides anyway, but assuming one or both is a variable, this is how you'd do it.)