hnwの日記

PHPの文字列型は2GB以上の文字列を処理できない


(2015/6/12追記)PHP7から、64bit環境であれば2GB以上の長さの文字列が扱えるようになります。やったね!


PHPの文字列型は、一般には文字列長の制限が無いとされています。PHPマニュアルにも次のように書いてあります。

注意: 文字列が非常に大きくなっても問題ありません。 PHP に課せられる文字列のサイズの実用上の制限はありません。 このため、長い文字列に関して恐れる必要は全くありません。


http://php.net/manual/ja/language.types.string.php


しかし、実際には2GBが上限であり、これ以上のサイズの文字列を扱うと奇妙な現象が発生します。

<?php
ini_set("memory_limit","2100M");
$str=str_repeat("xx",1073741824); // 2GB
var_dump(strlen($str)); // int(-2147483648)
var_dump(substr($str, 0, 1)); // bool(false)


例えば上の例では、2GBジャストの文字列の長さをstrlen関数で調べたらマイナスだと言われ、substr関数で最初の1文字を取得しようとしたら、そんな文字は無いと言われています。


どういうことかというと、PHPのzvalue_value共用体で文字列長をint型で管理しているため、文字列の長さが2147483647を超えるとマイナスになってしまうのです。これは32bit環境でも64bit環境でも同じです。

typedef union _zvalue_value {
        long lval;                              /* long value */
        double dval;                            /* double value */
        struct {
                char *val;
                int len;
        } str;
        HashTable *ht;                          /* hash table value */
        zend_object_value obj;
} zvalue_value;


マニュアルにわざわざ「実用上の」制限は無いと書いてあるのは、2GBを超える文字列なんて誰も扱わないよね、という意味かもしれません。メモリ1TBのマシンが気軽に扱えるようになったらPHP側で対策するかもしれませんね。