11

PHP と JavaScript は、型のジャグリングとキャストの際に 8 進数と 16 進数を扱うのが難しいことに気付きました。

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 には8 進数/16 進数の誤動作を修正するoctdec()と関数があることは知っていますが、JavaScript と同じように が 8 進数と 16 進数を処理することを期待しています。hexdec()intval()parseInt()

とにかく、この奇妙な行動の背後にある理論的根拠は何ですか?

4

3 に答える 3

9

035誰かが購入する製品の数量として指定していると想像してください(先頭0はパディング用であるため、リスト内の他の3桁の数量と一致します)。明らかに、プログラマー以外の035場合と同じように解釈されることが期待されます。35しかし、PHPが文字列の8進数を解釈すると、結果は突然29=> WTF?!?になります。一方、16進表記は、0x23表記を使用して数値を指定することは一般的ではないため、それほど問題にはなりません。

ちなみに、これはエンドユーザーだけでなく、プログラマーにも起こります。多くの場合、プログラマーは先行ゼロで数値を埋めようとしますが、すべてが間違っています。そのため、JSは厳密モードでの8進表記を許可しなくなり、他の言語ではより明示的な0oプレフィックスが使用されます。

ちなみに、私はこの振る舞いに一貫性がないことに同意します。私の目には、16進表記も解析されるべきではありません。8進数や2進数の表記と同じように、そうではありません。特に、明示的な(int)キャストは16進数も解析せず、代わりに最初の非桁まですべてを読み取ることを考慮します。


このケースに対処するintvalと、実際には文書化されているように動作intvalします。PHPのネイティブ整数表記を解析するためのものではなく、指定された基数の整数を解析するためのものです。ドキュメントを見ると、$baseデフォルトで。になっている2番目の引数が必要であることがわかります10。((int)ちなみに、キャストは内部的にはと同じconvert_to_long_base呼び出しにマップされるため、base = 10常にまったく同じように動作しますintval。)

于 2011-11-24T19:59:02.180 に答える
3

JavaScript では、10 進数と 16 進数のみが標準の一部として定義されていますが、8 進数は実装に依存します。

厳密モードでは 8 進数リテラルを取り除くことができますが、テストしたすべてのブラウザーでparseInt、10 進数ではなく 8 進数を解析しようとしました。厳密モードでは、暗黙の8進数を解釈しようとすることについて仕様が何も言っておらずparseInt、8進数の拡張を明示的に禁止しているため、これはちょっと奇妙です。"010"したがって、8 進数リテラルはなく、'd のときに 8 進数に変換しようとすることについての仕様も何もなくparseInt、動作は厳密モードでも持続します。

あなたがここで読むことができる仕様の私の解釈によれば、そうではありませんがNumber("012") === 12正しいですparseInt("012") === 10

ただし、16 進数には十分な理由があります。これにより、ビット レベルでの数値の操作がはるかに簡単になります。そして、「0xFF」は、16 進数を意味しない場合、誰かが入力するものではありません。

于 2011-11-24T20:11:03.033 に答える
1

他の回答は読みませんでしたが、少なくとも PHP では 8 進数または 16 進数に問題はありません。あなたはそれを間違っているだけです

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

文字列を整数にキャストすると...はい、PHP が常に行う方法で整数にキャストします。数値以外の文字が見つかるまで、任意の数値を取り、そこから整数を形成します。この場合、その唯一の0

hexdec()は文字列で機能しますが、この文字列は接頭辞なしの 16 進数のみ0xです。

echo hexdec('A0`); // 16

接頭辞0(8 進数) と0x(16 進数) は、異なる整数表記を区別するために存在しますが、文字列として記述している限り、PHP は文字列として扱います。

JavaScriptで同様の間違いをしたと思います。

于 2011-11-24T20:25:37.590 に答える