Search code examples
phpjavascriptcastinghexoctal

Why do PHP and JavaScript have problems dealing with octal and hexadecimal numbers?


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?


Solution

  • Imagine somebody specifies 035 as a quantity for some product to buy (the leading 0 is just for padding so it matches other three-digit quantities in the list). 035 is obviously expected to be interpreted just like 35 for a non-programmer. But if PHP were to interpret octal numbers in strings the result would suddenly be 29 => WTF?!? Hexadecimal notation on the other hand is less of a problem because people don't commonly specify numbers using a 0x23 notation.

    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 0o prefix.

    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 intval case, it actually behaves just like documented: intval isn'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 $base which defaults to 10. (The (int) cast by the way internally maps down to the same convert_to_long_base call with base = 10, so it will always behave exactly like intval.)