Почему PHP и JavaScript имеют проблемы с восьмеричными и шестнадцатеричными числами? - PullRequest
11 голосов
/ 24 ноября 2011

Я заметил, что PHP и JavaScript с некоторой трудностью обрабатывают восьмеричные и шестнадцатеричные числа при жонглировании и приведении типов:

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

Я знаю, что в PHP есть функции octdec() и hexdec() для исправления восьмеричного / шестнадцатеричного неправильного поведения, но я ожидаю, что intval() будет иметь дело с восьмеричными и шестнадцатеричными числами так же, как parseInt() в JavaScript.

В любом случае, в чем причина такого странного поведения?

Ответы [ 3 ]

9 голосов
/ 24 ноября 2011

Представьте себе, что кто-то указывает 035 как количество для покупки какого-либо продукта (ведущий 0 только для заполнения, поэтому он соответствует другим трехзначным количествам в списке).Очевидно, что 035 будет интерпретироваться так же, как и 35 для непрограммиста.Но если бы PHP интерпретировал восьмеричные числа в строках, результат внезапно был бы 29 => WTF?!?С другой стороны, шестнадцатеричная нотация представляет собой меньшую проблему, потому что люди обычно не указывают числа, используя нотацию 0x23.

Это, кстати, случается не только с конечными пользователями, но и с программистами.Часто программисты пытаются дополнить свои числа ведущими нулями и - да, все не так!Вот почему JS больше не разрешает восьмеричную запись в строгом режиме, а другие языки используют более явный префикс 0o.

Кстати, я согласен, что это поведение несовместимо.В моих глазах шестнадцатеричное обозначение также не должно быть проанализировано.Так же, как восьмеричной и двоичной записи нет.Особенно если учесть, что явное приведение (int) также не анализирует шестнадцатеричный код, а вместо этого просто читает все до первого нецифрового числа.


Обращаясь к случаю intval, оно фактически ведет себя так же, как документировано: intval не предназначен для анализа нативных целочисленных нотаций PHP, он предназначен для анализа целых чисел указанной базы .Если вы посмотрите на документы , вы обнаружите, что он принимает второй аргумент $base, который по умолчанию равен 10.(Между прочим, (int), брошенный, кстати, внутренне отображается на тот же convert_to_long_base вызов с base = 10, поэтому он всегда будет вести себя точно так же, как intval.)

3 голосов
/ 25 ноября 2011

В javascript только десятичные и шестнадцатеричные определены как часть стандарта, а восьмеричный зависит от реализации, что объясняет, почему восьмеричный синтаксический анализ не согласуется между примерами, которые вы дали.

Вы можете избавиться от восьмеричных литералов в строгом режиме, но во всех протестированных мною браузерах parseInt все еще пытался анализировать восьмеричные вместо десятичных. Что немного странно, потому что в спецификации ничего не говорится о попытке интерпретировать подразумеваемое восьмеричное значение для parseInt и явно запрещается восьмеричное расширение в строгом режиме. Так что нет восьмеричных литералов, ничего в спецификации о попытке превратить "010" в восьмеричное, когда parseInt 'd, и поведение сохраняется даже в строгом режиме.

Таким образом, Number("012") === 12 является правильным, в то время как parseInt("012") === 10 не является правильным, согласно моим интерпретациям спецификации, которую вы можете прочитать здесь

Для шестнадцатеричного кода есть веская причина, поскольку он значительно упрощает операции с числами на битовом уровне. И «0xFF» - это не то, что кто-то печатает, если он не имеет в виду гекс.

1 голос
/ 25 ноября 2011

Не прочитал другой ответ, но по крайней мере в PHP нет проблем с восьмеричными или шестнадцатеричными числами;вы просто делаете это неправильно

"0x12" // String with content "0x12"
0x12 // Integer "18"
010 // integer "8"

Приведение строки к целому числу будет ... да, приведение к целому числу, как это делает PHP всегда: он будет принимать любое число и формировать целое число из него до тех пор, поканаходит любой нечисловой символ.В этом случае его только 0

hexdec() работает со строками, но эти строки шестнадцатеричные только без префикса 0x.

echo hexdec('A0`); // 16

Префиксы 0 (восьмеричные) и 0x (шестнадцатеричное) существует для различения различных целочисленных обозначений друг от друга, но до тех пор, пока вы пишете это как строку, PHP будет обрабатывать ее как строку.

Я предполагаю, что вы сделалианалогичная ошибка с JavaScript.

...