PHPには他の言語と同様に様々な制限があります。まとまった資料が見つからなかったのでまとめておきます。PHPの制限と言っても実行時間の制限のようにマニュアルに記載されているINI設定などは記載していません。
PHPのデータ型制限
整数型
PHPの整数型のレンジはOSにより異なります。
- 32ビットOS – 符号付き32ビット整数。最大2^31-1、最小-2^31
- 64ビットOS – 符号付き64ビット整数。最大2^63-1、最小-2^63。ただし、PHP 7.0未満のWindows OSでは64ビットOSでも最大2^31-1、最小-2^31。
ネイティブの整数型を超える範囲の整数には任意精度整数(実質無制限)をサポートするGMPまたはBCmathが利用可能です。モジュールはデフォルトで組み込まれないですがGMPの利用を推奨。PHP 5.6からGMPオブジェクトもネイティブ整数型と同様に演算オペレーター(+, -, *, / など)が利用できます。
GMPにも制限があります。64bitプラットフォームでも2^37(16GB)までが取扱えるようです。大抵の場合、メモリ制限によりこれより遥かに小さい値までしか取り扱えません。
文字列型
PHPの文字列型は実際にはバイナリ型で、制御コードを含むどのようなバイトデータでも保存できます。
文字列型の最大長はOSとPHPのバージョンにより異なります。メモリ制限(php.iniのmemory_limit設定)により内部的に扱える最大データサイズは制限されます。Web環境の場合、php.iniのpost_max_size設定(メモリ設定)を超えるデータは扱えません。post_max_size設定の範囲内でも、max_input_time設定(処理時間設定)で処理できないデータは扱えません。
32ビットOS、PHP7.0未満で64ビットOSの場合
- 最大長は符号付き32ビット整数の最大値と同じ。最大2^31-1
PHP7.0以上で64ビットOSの場合
- 最大長は符号無し64ビット整数の最大値と同じ。最大2^64(実質的には無制限)
- ただし、mbstringが取り扱える最大文字列長は2^32に制限される(libmbflの文字列長定義にunsigned intが利用されているため)しかし、mbstringが利用するlibmbflのAPIはパラメータにint型(符号付き整数)を利用している。この為、4GBまでの文字列が保存できるが、文字列操作は2GBまでしかできない場合がある。
- mbstring以外でも内部的に利用しているライブラリ(C/C++)のデータ型制限などにより2GBまで4GBまでしか扱えない関数/機能もある。この場合、大きすぎるデータの場合にエラーまたは例外が発生する。
- 画像などのデータも”文字列型”を利用して保存される。ライブラリの制限を超える大きさのデータは処理できない。
浮動小数点型
PHPの浮動小数点型はIEEE 754の倍精度浮動小数点型です。
- 仮数部は最大2^52-1、-2^52(整数として正しく表現可能な範囲)
- 指数部は+1023 〜 −1022
配列型
PHPの配列型は”いわゆるメモリ領域が連続して割り当てられた配列”ではありません。内部的には順序付きのリスト(ハッシュ)として実装されています。この為、配列の添字が整数であってメモリに余裕があっても最大要素数が実装により制限されます。
配列型の要素数は内部で利用するハッシュのデータ構造定義に依存しています。
- PHP 7.0未満は2^32個まで (uint32_tが利用されているが、実際には最大数に達する前に問題が発生すると考えられる)
- PHP 7.0以上の場合、
- size_tが32bitの場合は、0x04000000個まで
- size_tが64bitの場合は、0x80000000個まで(通常は2^31個まで利用できる、と考えて良い)
要素数の最大値は添字に整数、文字列のどちらでも合わせた数までです。
PHP 7.0から配列型に”配列”(連続したメモリアドレスに要素が配置され、オフセットでアクセスできる本当の配列)が利用できるようになりました。これはユーザーから透過的に利用できます。配列添字が0から始まり、順番に要素が追加される時のみ”配列”になります。
PHPの配列型が”配列”になる例
$arr[] = 'a'; $arr[] = 'b'; $arr[] = 'c'; // $arr はハッシュではなく配列
しかし、PHPが利用するハッシュ関数は非常に高速なので、RubyやPythonのようにハッシュである場合と配列である場合に大きな実行速度の差はありません。(PHPはDJBX33A、Ruby/PythonはSipHashを利用している)
PHPが利用するDJBX33Aはハッシュ衝突攻撃に脆弱ですが、PHPプロジェクトでは暗号理論的にハッシュ衝突攻撃に強いSipHashではなく、ハッシュ衝突数の上限を設定することにより攻撃を防止しています。これは如何なるハッシュも危殆化による衝突攻撃の可能性があり、衝突数の制限による対策の方が優れている、とする判断があります。
ただし、配列(ハッシュ自体)への衝突検出と攻撃防止機能はPHP 7.0では実装されておらず、PHP 7.2での実装が検討されている状態です。
配列型の整数キー
PHPの配列型はハッシュと配列の両方を兼た、オーダードリスト(順序付きリスト)として実装されています。整数キーとなるキーは
- PHP_INT_MIN ≤ key ≤ PHP_INT_MAX
です。それ以外の整数は文字列として保存されます。ただし、オーバーフローする整数リテラル(コード中に記載した整数値)はオーバーフローした値をそのまま使い、エラーなどは発生しません。大きすぎまたは小さすぎる整数値が文字列として保存されるのは
- 文字リテラルの場合
- 文字列型のデータの場合
です。
透過的に処理されるのでユーザーが気にする必要はありませんが、PHP 7.0からPacked Array(内部構造的に本当のArray)がサポートされました。
<?php $arr[] = 1; $arr[] = 2; $arr[] = 3; ?>
などと0から順番に初期化された配列は自動的にPacked Arrayになります。Packed Arrayにできない場合は自動的に普通のオーダードリストの配列になります。
配列型の文字列型キー
連想配列のキー(文字列型キー)は文字列型と同じ制限が適用されます。利用できる文字種に制限はありません。つまり制御コードを含むバイナリ値もキーとして利用できます。
- 32bitの場合、2^31-1バイトまで利用可能
- 64bitの場合、2^63-1バイトまで利用可能
時間
UNIX時間は1970/1/1 00:00:00 UTCから始まる時間です。32bitプラットフォームでUNIX時間を符号付き整数で表している場合、2038年に扱えなくなります。
現在では64bit整数が使われており、符号付きの場合でもおよそ2800億年先に扱えなくなります。宇宙が滅亡しているくらい先の話なのでUNIX時間が64ビット整数の場合、実質的に無限の時間まで表せることになります。
strtotime()を実行すると判りますが、1970/1/1以前の時間も負の値として表せます。
$ php -r 'var_dump(strtotime("1950/1/1"));' int(-631184400)
UNIX時間が32bitである場合には1902年〜2038年程度までしか正しくUNIX時間が表せない点には注意が必要です。(32bitシステムが64bit整数をUNIX時間に使っていも、32bitシステムではPHPの整数は符号付き32bi整数t)
オブジェクト型
オブジェクト型のプロパティも配列と同じハッシュを使っているので最大のプロパティ数は配列と同じです。
- PHP 7.0未満は2^32個まで(uint32_tが利用されているが、実際には最大数に達する前に問題が発生すると考えられる)
- PHP 7.0以上の場合、
- size_tが32bitの場合は、0x04000000個まで
- size_tが64bitの場合は、0x80000000個まで(通常は2^31個まで利用できる、と考えて良い)
JSONデータ
PHPのJSONモジュールをオプション無しで利用すると整数型、浮動小数点型に見えるデータをPHPの整数型、浮動小数点型に変換します。このため、json_decode関数をオプション無しで利用すると整数の場合、
- 32bitのPHPでは符号付き32bit整数の範囲内しか扱えない
- 64bitのPHPでは符号付き64bit整数の範囲内しか扱えない
JSON_BIGINT_AS_STRINGオプションを指定すると範囲外の整数も文字列として扱えます。
浮動小数点型の場合、IEEE 745で表現できる範囲/精度に丸められます。
シンボルテーブルの制限
シンボルテーブルも配列型と同じハッシュを使っています。同じ制限になります。
- PHP 7.0未満は2^32個まで(uint32_tが利用されているが、実際には最大数に達する前に問題が発生すると考えられる)
- PHP 7.0以上の場合、
- size_tが32bitの場合は、0x04000000個まで
- size_tが64bitの場合は、0x80000000個まで(通常は2^31個まで利用できる、と考えて良い)
最大値に達する前に普通はメモリが足りなくなるので、実質的には無制限と考えて構いません。
ファイルの制限
OSファイル
PHPにラージファイルサポートが追加されたのはPHP4の頃です。OSファイルの取り扱いについてはoff64_t(符号無し64ビット整数)で取り扱えるサイズのファイルが利用できます。
ファイルシステムに制限がある場合はその制限が最大値になります。
データをファイルからファイルにコピーする場合にはPHPのメモリ制限は関係ありませんが、データをPHPプログラム内の変数に保存する場合は最大メモリ制限の範囲まで保存できます。
ファイルアップロード
ファイルアップロードで取り扱えるサイズはPHP 5.6で拡張されました。
- PHP 5.6未満は2GBまで
- PHP 5.6以降は実質的には無制限(ファイルシステムの制限と同じ)
関数/メソッドの再帰呼び出し
PHPは関数/メソッドの再帰呼び出しを制限していません。OSが許容したコールスタックサイズのチェックも行いません。PHPは使える限りのスタックを利用し、オーバーフローした場合はSegfault(クラッシュ)します。
利用できるOSのスタックサイズはOS設定なのでシステムによって異なります。
メモリ利用量(memory_limit)の制限
PHPにはメモリ制限があり、メモリにデータを取り込む場合はメモリ制限の値に制限されます。memory_limit設定により、PHPが利用する最大のメモリ使用量を制限できます。しかし、利用するOSに関わらず(つまり32ビットOS/64ビットOSに関わらず)PHP 7.0未満のPHPでは2GB以上に設定すると正常に動作しない場合があります。
- PHP 7.0未満のPHPの場合、実質的に2GBまでが最大値
- PHP 7.0以上の場合、実質的に無制限
PHPのメモリ制限によって制限されるメモリ利用量はPHP のメモリマネージャーによって管理されるメモリのみに制限されます。(つまり、システムのライブラリなどが利用するメモリの利用量はカウントされない)
データベース
PostgreSQL
PostgreSQLの制限はPostgreSQL自体の制限になります。
- text型は1GBまで
- bytea型は1GBまで
- ラージオブジェクトは2^63まで
- INT8の範囲は符号付き2^64
https://www.postgresql.org/about/
MySQL
MySQLの制限もMySQL自体の制限になります。
- INT8の範囲は符号付きまたは符号無し2^64
http://dev.mysql.com/doc/refman/5.7/en/limits.html
http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html
まとめ
メモ書き的に書いています。気がついたら更新すると思います。これが抜けている、という物があったら教えていただけると助かります。
参考: