为什么 PHP 和 JavaScript 在处理八进制和十六进制数字时出现问题?

发布于 2024-12-18 01:57:55 字数 896 浏览 4 评论 0原文

我注意到 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() 能够像 JavaScript 一样处理八进制和十六进制数字parseInt() 确实如此。

无论如何,这种奇怪行为背后的理由是什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

又怨 2024-12-25 01:57:55

想象一下,有人指定 035 作为某种产品购买的数量(前导 0 仅用于填充,以便与列表中的其他三位数数量匹配)。对于非程序员来说,035 显然应该像 35 一样被解释。但是如果 PHP 解释字符串中的八进制数字,结果会突然变成 29 =>搞什么鬼?!?另一方面,十六进制表示法的问题较小,因为人们通常不使用 0x23 表示法来指定数字。

顺便说一句,这种情况不仅发生在最终用户身上,也发生在程序员身上。程序员经常尝试用前导零填充数字,然后 - 嗯,一切都错了!这就是为什么 JS 不再允许严格模式下的八进制表示法,而其他语言则使用更明确的 0o 前缀。

顺便说一句,我确实同意这种行为是不一致的。在我看来,十六进制表示法也不应该被解析。就像八进制和二进制表示法不是一样。特别是考虑到显式 (int) 转换也不解析十六进制,而是仅读取第一个非数字之前的所有内容。


针对 intval 的情况,它实际上的行为就像记录的那样:intval 不是用于解析 PHP 的本机整数表示法,它用于解析指定基数的整数。如果您查看文档,您会发现它需要第二个参数$base< /code> 默认为 10。 ((int) 顺便在内部映射到相同的 convert_to_long_base 使用 base = 10 调用,因此它的行为始终与intval。)

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.)

哭了丶谁疼 2024-12-25 01:57:55

在javascript中,只有十进制和十六进制被定义为标准的一部分,而八进制是依赖于实现的,这可以解释为什么八进制解析在您给出的示例之间不一致。

您可以在严格模式下摆脱八进制文字,但在我测试的所有浏览器中,parseInt 仍然尝试解析八进制而不是十进制。这有点奇怪,因为规范没有说明如何尝试解释 parseInt 的隐含八进制,并且在严格模式下明确禁止八进制扩展。因此,没有八进制文字,规范中没有任何关于在解析 Int 时尝试将 "010" 转换为八进制的内容,并且即使在严格模式下,该行为仍然存在。

因此,根据我对规范的解释, Number("012") === 12 是正确的,而 parseInt("012") === 10 是不正确的可以阅读此处

有一个很好的理由虽然是十六进制,但它使位级数字的操作变得更加容易。如果某人不表示十六进制,则不会输入“0xFF”。

In javascript, only decimal and hex are defined as part of the standard, while the octal is implementation dependent, which would explain why octal parsing is not consistent between the examples you gave.

You can get rid of octal literals in strict mode but in all browsers I tested, parseInt still tried to parse an octal instead of decimal. Which is kind of strange because the spec does not say anything about trying to interpret implied octal for parseInt and explicitly prohibits the octal extension when in strict mode. So no octal literals, nothing in the spec about trying to turn "010" into an octal when parseInt'd, and the behavior persists even in strict mode.

So Number("012") === 12 is correct while parseInt("012") === 10 is not correct according to my interpretations of the spec which you can read here

There is a good reason for hexadecimal though, it makes operations on numbers at bit level much easier. And "0xFF" is not something someone types if he doesn't mean a hex.

终难遇 2024-12-25 01:57:55

没有阅读其他答案,但至少在 PHP 中八进制或十六进制数字没有问题;你只是做错了

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

将字符串转换为整数将...是的,将其转换为整数,就像 PHP 总是这样做的那样:它将采用任何数字并从中形成整数,直到找到任何非数字字符。在这种情况下,它唯一的 0

hexdec() 适用于字符串,但该字符串仅是没有前缀 0x 的十六进制。

echo hexdec('A0`); // 16

前缀 0(八进制)和 0x(十六进制)的存在是为了区分不同的整数表示法,但只要你将其写为字符串,PHP 就会将其视为它作为一个字符串。

我猜你在 javascript 上也犯过类似的错误。

Didn't read the other answer, but at least in PHP there is no problem with octal or hexadecimal numbers; you just doing it wrong

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

Casting the string to integer will ... yes, cast it to integer the way PHP always does it: It will take any number and form the integer out of it until it founds any non-numeric character. In this case its only 0

hexdec() works on strings, but this strings are hexadecimal only without the prefix 0x.

echo hexdec('A0`); // 16

The prefixes 0 (octal) and 0x (hexadecimal) exists to distinguish the different integer notations from each other, but as long as you write it as a string, PHP will treat it as a string.

I assume, that you did a similar mistake with javascript.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文