お前は php の歴史的な理由の数を覚えているのか

Post on 15-Jan-2015

20.062 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

PHP といえば印象的なのは「歴史的な理由」 (≒黒歴史) の数々ですね。 このセッションでは、普段闇にこもっていてスポットの当たることの少ない「歴史的な理由」たちを引きずり出し、徹底追及し、頭を抱えていこうと思います。

TRANSCRIPT

お前は PHP の歴史的な 理由の数を覚えているのか

Kousuke Ebihara (海老原昂輔)

<kousuke@co3k.org>

5 個

5 個_人人人人人人人人人人_

> 言うほどなかった <

 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

※ドキュメントから数えただけなので実体としてはもっとありそうですが、今回は考えません

自己紹介

•Kousuke Ebihara (海老原昂輔) a.k.a. @co3k

•株式会社 VOYAGE GROUP (2014/02 より)

•スマホコミュケーション事業室で Python 書いてます

•そういえば PHP 全然書いてないです

•セキュリティ周り

•以前は某 OSS の SNS エンジンとかその辺やってました

歴史的な理由のある機能

• implode()

•urlencode() / rawurlencode()

•double 型 / float 型 と、 gettype() の返り値

•Phar アーカイブのマニフェスト情報

•Zend Engine の HashTable (間に合わず)

調査方法

•PHP 4 以降については普通に Git で潜っていく

•php-src : 公式の Git リポジトリ

•ドキュメント: git-svn で公式のリポジトリを変換

•PHP 3 以前

•museum.php.net (かなり重いので注意)

•ML

•1996/07 - 1998/01: PHP/FI Mailing List

•1996/12 以降: php-internals (marc.info なら旧 php-dev 時代も追える)

implode()

implode() の歴史的な理由

• 「implode() は、歴史的な理由により、引数をどちらの順番でも受けつけることが可能です」

•おそらく PHP で一番有名な「歴史的な理由」

implode() の実装PHP_FUNCTION(implode)!{!********************** SNIP *********************!

if (arg2 == NULL) {!********************** SNIP *********************!

} else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {!********************** SNIP *********************!

}! }!! php_implode(delim, arr, return_value TSRMLS_CC);

implode() の実装PHP_FUNCTION(implode)!{!********************** SNIP *********************!

if (arg2 == NULL) {!********************** SNIP *********************!

} else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {!********************** SNIP *********************!

}! }!! php_implode(delim, arr, return_value TSRMLS_CC);

第 2 引数が指定されている

implode() の実装PHP_FUNCTION(implode)!{!********************** SNIP *********************!

if (arg2 == NULL) {!********************** SNIP *********************!

} else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {!********************** SNIP *********************!

}! }!! php_implode(delim, arr, return_value TSRMLS_CC);

第 2 引数が指定されている

配列が第 1 引数に指定されていればデリミタは第 2 引数

implode() の実装PHP_FUNCTION(implode)!{!********************** SNIP *********************!

if (arg2 == NULL) {!********************** SNIP *********************!

} else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {!********************** SNIP *********************!

}! }!! php_implode(delim, arr, return_value TSRMLS_CC);

第 2 引数が指定されている

配列が第 1 引数に指定されていればデリミタは第 2 引数

配列が第 2 引数に指定されていればデリミタは第 1 引数

implode() の実装PHP_FUNCTION(implode)!{!********************** SNIP *********************!

if (arg2 == NULL) {!********************** SNIP *********************!

} else {! if (Z_TYPE_PP(arg1) == IS_ARRAY) {! arr = *arg1;! convert_to_string_ex(arg2);! delim = *arg2;! } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {! arr = *arg2;! convert_to_string_ex(arg1);! delim = *arg1;! } else {!********************** SNIP *********************!

}! }!! php_implode(delim, arr, return_value TSRMLS_CC);

第 2 引数が指定されている

配列が第 1 引数に指定されていればデリミタは第 2 引数

配列が第 2 引数に指定されていればデリミタは第 1 引数

配列が指定されていなければエラー

implode() の歴史

•PHP/FI 2 には implode() も explode() も存在しない

•PHP 3 にはある

•PHP 3 時点では implode() は現在と同じ挙動に

•つまりこの「歴史的な理由」は PHP/FI 2 → PHP 3 の開発中に生まれたものと思われる

PHP 3.0a3 (November 23 1997)

•Switched between the 1st and 2nd parameters to explode(), so that it acts like split() (拙訳: explode() の第 1 引数と第 2 引数を交換したので、 split() と同じように動作するようになりました)

split() と explode()

split() と explode()

元々は逆 (implode() が歴史的な理由により受け付ける順序と同じ�)

PHP 3.0b5 (February 24 1998)

•Made implode() accept arguments in the order used by explode() as well (拙訳: implode() が explode() で使われているような引数順も受け付けるようにしました)

explode() と implode() に 何が起こったか

• PHP 3.0 開発中に explode(), implode(), split() が追加された

• このタイミングで追加、変更された機能は多いので当時の CHANGELOG を眺めているだけでも結構楽しい

• PHP 3.0a3 にて、 explode() の引数順を split() に合わせた

•この結果、 implode() との統一性が取れなくなったので、PHP 3.0b5 にて、 implode() では両方の引数順を受け付けるようにした

• explode() が据え置きだったのは、引数が両方とも文字列型だから?

•わずか 3 ヶ月の「歴史」

urlencode() / rawurlencode()

URL エンコード用の 2 つの関数

•urlencode()

•文字列を URL エンコード

• rawurlencode()

•文字列を URL エンコード

URL エンコード用の 2 つの関数

•urlencode()

•文字列を URL エンコード

• rawurlencode()

•文字列を URL エンコード

(RFC 3986 に基づかない)

URL エンコード用の 2 つの関数

•urlencode()

•文字列を URL エンコード

• rawurlencode()

•文字列を URL エンコード

(RFC 3986 に基づかない)

(RFC 3986 に基づく)

どのような違いがあるか?•urlencode()

•空白 (U+0020) を + (U+003B) に置き換える

•~ (U+007E) をエンコードする (RFC 1738 に基づく)

• rawurlencode()

•空白 (U+0020) をパーセントエンコードする

•~ (U+007E) をエンコードしない (RFC 3986 に基づく)

どのような違いがあるか?•urlencode()

•空白 (U+0020) を + (U+003B) に置き換える

•~ (U+007E) をエンコードする (RFC 1738 に基づく)

• rawurlencode()

•空白 (U+0020) をパーセントエンコードする

•~ (U+007E) をエンコードしない (RFC 3986 に基づく)

追従漏れじゃね……?

urlencode() の歴史的な理由

• 「歴史的な理由により、この関数は RFC 3986 エンコード (rawurlencode() を参照してください) とは異なり、空白を + 記号にエンコードします」

urlencode() の実装 (EBCDIC モード時の処理は省略)

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)!{!

********************** SNIP *********************! while (from < end) {! c = *from++;!! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! }

urlencode() の実装 (EBCDIC モード時の処理は省略)

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)!{!

********************** SNIP *********************! while (from < end) {! c = *from++;!! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! }

while ループで文字列終端まで from を 1 文字ずつ走査

urlencode() の実装 (EBCDIC モード時の処理は省略)

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)!{!

********************** SNIP *********************! while (from < end) {! c = *from++;!! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! }

while ループで文字列終端まで from を 1 文字ずつ走査

スペースを + に置換して to に格納

urlencode() の実装 (EBCDIC モード時の処理は省略)

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)!{!

********************** SNIP *********************! while (from < end) {! c = *from++;!! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! }

while ループで文字列終端まで from を 1 文字ずつ走査

スペースを + に置換して to に格納

それ以外のエンコード対象の文字はパーセントエンコードして to に格納

urlencode() の実装 (EBCDIC モード時の処理は省略)

PHPAPI char *php_url_encode(char const *s, int len, int *new_length)!{!

********************** SNIP *********************! while (from < end) {! c = *from++;!! if (c == ' ') {! *to++ = '+';! } else if ((c < '0' && c != '-' && c != '.') ||! (c < 'A' && c > '9') ||! (c > 'Z' && c < 'a' && c != '_') ||! (c > 'z')) {! to[0] = '%';! to[1] = hexchars[c >> 4];! to[2] = hexchars[c & 15];! to += 3;! } else {! *to++ = c;! }! }

while ループで文字列終端まで from を 1 文字ずつ走査

スペースを + に置換して to に格納

それ以外のエンコード対象の文字はパーセントエンコードして to に格納

エンコードしない文字はそのまま to に格納

PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)!{! register int x, y;! unsigned char *str;!! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! }

rawurlencode() の実装 (EBCDIC モード時の処理は省略)

PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)!{! register int x, y;! unsigned char *str;!! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! }

rawurlencode() の実装 (EBCDIC モード時の処理は省略)

for ループで文字列終端まで 1 文字ずつ走査

PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)!{! register int x, y;! unsigned char *str;!! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! }

rawurlencode() の実装 (EBCDIC モード時の処理は省略)

for ループで文字列終端まで 1 文字ずつ走査

とりあえず str に文字を格納

PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)!{! register int x, y;! unsigned char *str;!! str = (unsigned char *) safe_emalloc(3, len, 1);! for (x = 0, y = 0; len--; x++, y++) {! str[y] = (unsigned char) s[x];! if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||! (str[y] < 'A' && str[y] > '9') ||! (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||! (str[y] > 'z' && str[y] != '~')) {! str[y++] = '%';! str[y++] = hexchars[(unsigned char) s[x] >> 4];! str[y] = hexchars[(unsigned char) s[x] & 15];! }! }

rawurlencode() の実装 (EBCDIC モード時の処理は省略)

for ループで文字列終端まで 1 文字ずつ走査

エンコード対象の文字ならパーセントエンコード

とりあえず str に文字を格納

(つд⊂)ゴシゴシゴシ

(;゚Д゚) 共通化されてねぇ……!

なぜ空白を + に置き換えるか

技術/HTTP/URLエンコードで 0x20(スペース) を "+" にすべきか "%20" にすべきか - Glamenv-Septzen.net http://www.glamenv-septzen.net/view/1170※PHP に関する記述 (rawurlencode() が用意された経緯など) は若干事実と異なる部分がある。本スライドで詳述

なぜ空白を + に置き換えるか

• application/x-www-form-urlencoded のため

•W3C の規格 (たとえば HTML 5) などに含まれる (単独の規格は存在しない)

• form が submit された場合のレスポンスボディのエンコード方式

•空白を + に置き換えるほかはだいたいパーセントエンコード

他の言語の状況•Python 2 (Python 3 では urllib.parse)

•RFC 3986 の URL エンコード: urllib.quote()

• application/x-www-form-urlencoded: urllib.quote_plus()

•Ruby

•RFC 3986 の URL エンコード: ERB::Util.u(), URI.encode()

• application/x-www-form-urlencoded: URI.encode_www_form(), CGI.escape()

•ただし URI.encode() は obsolete で、 ERB::Util.u() とかが代替となっている模様

urlencode() の歴史

•PHP/FI 2.0 から存在

•この当時から空白 (U+0020) を + (U+003B) に置き換える実装になっていた

char *php_urlencode(char *s) {!********************** SNIP *********************! for(x=0,y=0; s[x]; x++,y++) {! str[y] = s[x];! if(str[y]==' ') {! str[y]='+';

rawurlencode() の歴史

•PHP 3.0b3 から存在 (当時は RFC 1738 ベース)

•まーた PHP 3.0 か!

•RFC 3986 は 2005 年 1 月

•PHP 3.0 は 1999 年 (PHP 3.0b3 は 1998 年)

•PHP 5.0 のタイミングで RFC 3986 ベースに変更

rawurlencode() 誕生秘話 (序章)

•1997/06/16 (PHP/FI 2.0b12)

•UrlEncode() がスペースを + に置換するようになる

•1997/11/12 (PHP/FI 2.0)

•UrlEncode() が / をエンコードしないようになる (後に撤回)

•URL 文字列全体のエンコードを意図した議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2

rawurlencode() 誕生秘話 (事件篇)

•1998/01/15 頃 (PHP 3.0b3 開発中)

• Jaakko Hyvätti が urlencode() で & をエンコードしないように変更? (意図の説明を user ML にポストしたようだが入手できず)

•PHP/FI 2.0 での変更の意図に合わせたもの

•おそらくここで rawurlencode() と formencode() (おそらくリリース前に削除) が入ったと思われる ([PHP-DEV] ML で my rawurlencode() などと説明しているので)

•PHP 3.0b3-dev の urlencode() が壊れたと報告がくる議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2

rawurlencode() 誕生秘話 (解決篇)

•1998/01/16

•PHP 2.0 の変更が不適切ということになり、スペースを + に置換する版まで戻される

•ちなみに Jaakko は「rawurl*code() っていい名前ない?�urlpath*code() とか?」とも言ってるが Rasmus 華麗にこれをスルー

•スペースを + にする件も戻した方がいいのでは、という Jaakko の提案に Rasmus は反対

• 「スペースが + になっていれば urldecode() なしで POST data が使える」、「URL 中の + は自動的にスペースにデコードされる」(= つまり + なら URL と POST data どっちもいける)

•既存のコードが壊れる議論のスレッドは http://marc.info/?t=90279138700001&r=1&w=4 http://marc.info/?t=90279138700002&r=1&w=2

urlencode() と rawurlencode() についてのまとめ

•URL 中の文字列のエンコードをおこなう際は、 rawurlencode() を使ったほうがよい

•urlencode() を使うべき場面は滅多にない

•名前的に urlencode() の方が正しそうなので多用されがちだが……

•自力で POST データのエンコードをしたい場合くらい

•そもそも RFC�3986 にも追従していない

問題のあった事例

•Bug(バグ) #3383: mail_to 関数を用いるときに空白が + に変換されてしまう - OpenPNE 3 https://redmine.openpne.jp/issues/3383

•ここで気がついた (symfony の link_to() は urlencode() を使っている)

•空白を意図して渡していても + をスペースに展開しないメーラがあったと思われる

DOUBLE 型と FLOAT 型

PHP における浮動小数点数

•精度は環境依存だが、通常 IEEE 754 の double (倍精度浮動小数点数)

•PHP では float 型ということで統一されている

•型キャストの際に (double) や (real) しても float になる

浮動小数点数の (?) 歴史的な理由

• 「double は float と同じものだと考えてください。 2 種類の名前が存在するのは、歴史的な理由によるものです」

float / double 型の歴史

•PHP/FI 2.0 (1997/11/12) : double

•PHP 3.0 (1998/06/06) : double (float, real でもキャストできるように)

•PHP 4.1.0 (2001/12/10): float……?

•2c275bf793f70ad2a38bbf4a0f7ad12fecaca095, 03f7406711d3706af0f237e1ea03974616dd2139 など

なんで double -> float に なったか

•不明……

•ML では議論されてない?

•突如として float 派が出現したように見える [要出典]

•無理に double を float に置換する必要があったのかどうか疑問

float 派の闘いの記録

•Hartmut Holzgraefe

•double -> float への置換をおこなった最初の人物

•多くの double -> float の置換に貢献

• Jeroen van Wolffelaar

•ドキュメントに存在するほとんどの double を float に置換した

•Gabor Hojtsy

float 派の登場

•Hartmut Holzgraefe による 2001/09/21 のコミット (2c275bf7) で、 floatval(), is_float() のエイリアスとして doubleval(), is_double() を使うように変更 (それまでは逆)

•さらに (03f74067) で関数定義部分のコメント (返り値や引数型などが書かれている) の double を float に置換

float 派の登場

新たな double の出現

float 派の反撃

php has no ‘double’, only ’float’

しかし止まらない double の追加

そして 1 年が経ったある日

“php has no ‘double’” とはなんだったのか

ドキュメントの置換も忘れない

• r53773 (2001/08/07) by Jeroen van Wolffelaar

• r54456 (2001/08/12) by Jeroen van Wolffelaar

• r54918 (2001/08/14) by Jeroen van Wolffelaar

• r57972 (2001/09/21) by Hartmut Holzgraefe

• r57997 (2001/09/21) by Jeroen van Wolffelaar

• r57999 (2001/09/21) by Jeroen van Wolffelaar

ぜんぶ歴史のせいだ。

未だ残る double の痕跡

• 「歴史的な理由により、 float の場合には “double” が返されます。 “float” とはなりません」

Phar アーカイブのマニフェスト情報

Phar アーカイブのマニフェスト情報における歴史的な理由

• 「Phar マニフェストは高度に最適化された書式で (略) 1 バイトをこえる大きさの値はリトルエンディアン形式のバイト順で保存されます。ただし API バージョンだけは例外です。これは 3 ニブルのデータですが、歴史的な理由によりビッグエンディアン形式のバイト順で保存されます」

Phar アーカイブの構造

スタブ

マニフェスト

コンテンツ

シグネチャ (optional)

Phar アーカイブの構造

スタブ

マニフェスト

コンテンツ

シグネチャ (optional)

Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了

Phar アーカイブの構造

スタブ

マニフェスト

コンテンツ

シグネチャ (optional)

Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了

バージョン情報などのメタ情報

Phar アーカイブの構造

スタブ

マニフェスト

コンテンツ

シグネチャ (optional)

Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了

バージョン情報などのメタ情報

アーカイブの内容

Phar アーカイブの構造

スタブ

マニフェスト

コンテンツ

シグネチャ (optional)

Phar アーカイブの起動時に実行される PHP スクリプト。 __HALT_COMPILER(); で終了

バージョン情報などのメタ情報

アーカイブの内容

パッケージ検証用のシグネチャ。 Phar 形式のみ

Phar アーカイブのマニフェストマニフェストの長さ (Little Endian)

格納するファイルの数 (Little Endian)

ビットマップフラグ (Little Endian)

API バージョン (Big Endian)

エイリアスの長さ (Little Endian)

エイリアス (※任意桁)

メタデータの長さ (Little Endian)

メタデータ (※任意桁)

ファイルのリスト (※任意桁)

Phar アーカイブのマニフェストマニフェストの長さ (Little Endian)

格納するファイルの数 (Little Endian)

ビットマップフラグ (Little Endian)

API バージョン (Big Endian)

エイリアスの長さ (Little Endian)

エイリアス (※任意桁)

メタデータの長さ (Little Endian)

メタデータ (※任意桁)

ファイルのリスト (※任意桁)

ニブル単位でバージョンを表現

Phar アーカイブのマニフェストマニフェストの長さ (Little Endian)

格納するファイルの数 (Little Endian)

ビットマップフラグ (Little Endian)

API バージョン (Big Endian)

エイリアスの長さ (Little Endian)

エイリアス (※任意桁)

メタデータの長さ (Little Endian)

メタデータ (※任意桁)

ファイルのリスト (※任意桁)

ニブル単位でバージョンを表現 検証用のシグネチャが含まれているか、圧縮されたファイルが存在するかなどのフラグ

Phar アーカイブのマニフェスト (composer.phar (1.0.0-alpha8) の例)

0x17F-82 : マニフェストの長さ (26489)

0x183-86 : ファイル数 (322)

0x187-88: API バージョン (1.1.0) ※最後の 4bit は未使用

0x189-8C : ビットマップフラグ (0x00010000 : この Phar には検証用シグネチャが含まれる)

0x18D-90 : この Phar のエイリアスの長さ (13)

0x191-9D : エイリアス (composer.phar)

バージョン情報のみ ビッグエンディアンである理由

•3842b67 には元になった PHP_Archive に由来する理由とある

•PHP_Archive の最新の実装もバージョン情報だけビッグエンディアンで格納している (PHP_Archive_Creator::serializeManifest())

•PHP_Archive の 2f41f8f48 ではアーカイブ作成時にビッグエンディアンで格納しているが、展開時にはリトルエンディアンでパースしようとしている

•PHP_Archive の 8931abf6 で展開時にもビッグエンディアンでパースするよう修正された

•つまり、間違えてビッグエンディアンで格納してしまったために後に引けなくなったのでは……

ZEND ENGINE の HASHTABLE

Zend Engine の HashTable API における歴史的な理由

• 「hash exists for historical reasons and is always ignored」(拙訳: 引数 hash は歴史的な理由のために存在し、常に無視される)

Zend Engine の HashTable API における歴史的な理由

•時間切れで追い切れず

•まあなんとなくわかる

まとめ

•身近な機能とかを深追いしていくのは結構楽しい

•PHP 3.0 時代のチェンジログと ML は本当にオススメ

•たとえば「昔の PHP は + 演算子で文字列結合できたんだよー」とか無駄知識を披露してドヤ顔できる

•5 個がっつり深追いしていくだけでも結構時間が埋まるので助かった

•Phar とか Zend Engine 周りの歴史的な理由が出てきたおかげで割と闇 PHP っぽくなった気がする

top related