I have noticed that PHP and JavaScript treat octal and hexadecimal numbers with some difficulty while type juggling and casting:
PHP:
echo 16 == '0x10' ? 'true' : 'false'; //true, as expected
echo 8 == '010' ? 'true' : 'false'; //false, o_O
echo (int)'0x10'; //0, o_O
echo intval('0x10'); //0, o_O
echo (int)'010'; //10, o_O
echo intval('010'); //10, o_O
JavaScript:
console.log(16 == '0x10' ? 'true' : 'false'); //true, as expected
console.log(8 == '010' ? 'true' : 'false'); //false, o_O
console.log(parseInt('0x10')); //16, as expected
console.log(parseInt('010')); //8, as expected
console.log(Number('0x10')); //16, as expected
console.log(Number('010')); //10, o_O
I know that PHP has the octdec() and hexdec() functions to remedy the octal/hexadecimal misbehaviour, but I’d expect the intval() to deal with octal and hexadecimal numbers just as JavaScript’s parseInt() does.
Anyway, what is the rationale behind this odd behaviour?
Imagine somebody specifies
035as a quantity for some product to buy (the leading0is just for padding so it matches other three-digit quantities in the list).035is obviously expected to be interpreted just like35for a non-programmer. But if PHP were to interpret octal numbers in strings the result would suddenly be29=> WTF?!? Hexadecimal notation on the other hand is less of a problem because people don’t commonly specify numbers using a0x23notation.This by the way doesn’t only happen to end users, but to programmers too. Often programmers try to pad their numbers with leading zeros and – huh, everything is wrong! That’s why JS doesn’t allow octal notation in strict mode anymore and other languages use the more explicit
0oprefix.By the way, I do agree that this behavior is inconsistent. In my eyes hexadecimal notation shouldn’t be parsed either. Just like octal and binary notation is not. Especially considering that the explicit
(int)cast doesn’t parse hex either and instead just reads everything up to the first non-digit.Addressing the
intvalcase, it actually behaves just like documented:intvalisn’t there for parsing PHP’s native integer notations, it is for parsing integers of a specified base. If you have a look at the docs, you’ll find that it takes a second argument$basewhich defaults to10. (The(int)cast by the way internally maps down to the sameconvert_to_long_basecall withbase = 10, so it will always behave exactly likeintval.)