🍣

【PHP8】8進数も基数表示を明記したい

3 min read

PHPの数値リテラルは、いくつかの基数をサポートしています。

全部16
$a = 16;         // 10進数
$a = 0x10;       // 16進数
$a = 0b00010000; // 2進数
$a = 020;        // 8進数

8進数だけおかしくない?
ということでExplicit octal integer literal notationというRFCが提出されました。

Explicit octal integer literal notation

Introduction

PHPの8進数リテラル表記は、"016" == 016がfalseになるなどよくわからない結果になることがあります。
これは016が8進数であり、10進数でいう14になるからです。

この表記は、Java、C、C#、Golang、Haskellその他諸々の言語と同じ規則であり、たしかに確立された文法ではあります。
一方PythonJavaScriptRust0o表記のみをサポートしています。

PHPのoctdecbase_convert関数は、実はしれっと0o表記をサポートしていたりします。

Proposal

16進数の0x、2進数の0bと同じように、8進数リテラルを表す接頭辞0oをサポートします。

0o16 === 14; // true
0o123 === 83; // true

016 === 0o16; // true

Behaviour of numeric strings

PHP7.0では、文字列での基数表記はサポートされていません
数値型文字列における基数サポートは、複雑で混乱を招くため却下されました。

However supporting octal numbers is not possible, because handling the string '0123' as the number 83 would be highly unexpected for end users of an application.
8進数のサポートは不可能です。
なぜなら文字列'0123'を数値83と解釈することは、ユーザにとって全く予期せぬ結果になります。

従ってこのRFCも、文字列に対しては何の影響も及ぼしません。
'0o16'は今後もただの文字列です。

Backward Incompatible Changes

互換性のない変更はありません。

Proposed PHP Version(s)

PHP8.x

RFC Impact

To Existing Extensions

GMPエクステンションは8進数表記への対応が必要。
FILTER_VALIDATE_INTフラグのFILTER_FLAG_ALLOW_OCTALは対応が必要。

To Opcache

特になし。

Unaffected PHP Functionality

現在の、暗黙の8進数表記の動作に変更はありません。

Future Scope

・いずれ暗黙の8進数表記を非対応にする。
・数値型文字列において進数表記をサポートする。

Patches and Tests

GitHubには既にパッチが上がっています。

感想

えっマジかよ。
マジだった

var_dump(octdec('020')); // 16
var_dump(octdec('0o20')); // 16
var_dump(base_convert('020', 8, 10)); // "16"
var_dump(base_convert('0o20', 8, 10)); // "16"

マニュアルにもユーザノートにも一切書かれていない超絶秘密機能が隠されていたとはびっくりだよ。
こういうのって、探せば他にもあるかもしれませんね。

さて、このRFCはまだ提出されただけです。
今後受理されるか却下されるかは、投票を待たなければいけません。
しかし特に反対するような理由もないだろうし、さらにSara GolemonNikitaの二人が早々と賛成しているので、まず間違いなく通るでしょう。

そしてそんなに重たい内容でもなさそうなので、おそらくPHP8.1あたりでさくっと導入されると思います。
今後は以下のようにわかりやすく表記できるようになることでしょう。

全部16
$a = 16;         // 10進数
$a = 0x10;       // 16進数
$a = 0b00010000; // 2進数
$a = 0o20;        // 8進数

0とoがわかりにくいな。