PHP5.3.0から実装されたSplFixedArrayというSPLクラスがあります。これはマニュアルによれば下記のようなクラスです。
SplFixedArray クラスは配列の主要な機能を提供します。 SplFixedArray と通常の PHPの配列との主な違いは、 SplFixedArray は固定長であって、整数値で指定した範囲内の添字しか使用できないところです。これにより、より高速な配列の実装が可能となりました。
制限はあるけれども高速な配列もどきのクラスだと紹介してありますね。このクラスについて少し調べてみました。
SplFixedArrayの速度
まずはSplFixedArrayが本当に速いのかどうか、下記のようなプログラムで実験してみました。実験はPHP5.3.0で行いました。
<?php for($size = 5; $size < 20000; $size *= 2) { echo PHP_EOL . "Testing size: $size" . PHP_EOL; unset($container); $start_time = microtime(true); for ($container = array(), $i = 0; $i < $size; $i++) { $container[$i] = $i; } echo "Array(): " . (microtime(true) - $start_time) . PHP_EOL; unset($container); $start_time = microtime(true); for($container = new SplFixedArray($size), $i = 0; $i < $size; $i++) { $container[$i] = $i; } echo "SplArray(): " . (microtime(true) - $start_time) . PHP_EOL; }
配列とSplFixedArrayの全要素に値を書き込むテストです。結果は下記の通りです。
Testing size: 5 Array(): 2.6941299438477E-5 SplArray(): 4.1961669921875E-5 Testing size: 10 Array(): 5.0067901611328E-6 SplArray(): 5.9604644775391E-6 Testing size: 20 Array(): 9.0599060058594E-6 SplArray(): 7.1525573730469E-6 Testing size: 40 Array(): 2.288818359375E-5 SplArray(): 1.0967254638672E-5 Testing size: 80 Array(): 2.6941299438477E-5 SplArray(): 1.7166137695312E-5 Testing size: 160 Array(): 6.1988830566406E-5 SplArray(): 3.1948089599609E-5 Testing size: 320 Array(): 0.0020380020141602 SplArray(): 6.7949295043945E-5 Testing size: 640 Array(): 0.00023484230041504 SplArray(): 0.00011801719665527 Testing size: 1280 Array(): 0.00044584274291992 SplArray(): 0.00022792816162109 Testing size: 2560 Array(): 0.00090503692626953 SplArray(): 0.00048589706420898 Testing size: 5120 Array(): 0.0018289089202881 SplArray(): 0.0011360645294189 Testing size: 10240 Array(): 0.004019021987915 SplArray(): 0.002223014831543
クラス生成のオーバーヘッドがあるので常に配列より有利というわけにはいきませんが、確かにSplFixedArrayは高速です。ベンチマークとしてはアバウトな実験ですが、配列サイズが20を超えたあたりで配列よりSplFixedArrayの方が高速になり、配列サイズ160あたりからはSplFixedArrayの方が倍くらい高速になるようです。
内部構造としては、SplFixedArrayはzvalのポインタの配列として実現されています。一方、PHPの通常の配列は、配列としての構造と連想配列としての構造をそれぞれlinked listで持つような複雑な構造になっています。このような構造の差が上記の速度差の原因だと考えられます。
ただし、SplFixedArrayはクラスなので、要素へアクセスする際のメソッド呼び出しのオーバーヘッドが避けられません。実験したところでは、既存要素の読み書きは配列の方が高速なようです。
SplFixedArrayのメモリ消費
しかし、実際のアプリケーションでは他の処理も行うはずですから、この程度の速度差は隠蔽されることが多いのではないでしょうか。また、CPUよりもメモリの方がリソースとして貴重な環境も多いかと思います。そこで、配列とSplFixedArrayのメモリ消費の差を測定してみます。
<?php for($size = 5; $size < 20000; $size *= 2) { echo PHP_EOL . "Testing size: $size" . PHP_EOL; unset($container); $start_memory = memory_get_usage(); for ($container = array(), $i = 0; $i < $size; $i++) { $container[$i] = $i; } echo "Array(): " . (memory_get_usage() - $start_memory) . PHP_EOL; unset($container); $start_memory = memory_get_usage(); for($container = new SplFixedArray($size), $i = 0; $i < $size; $i++) { $container[$i] = $i; } echo "SplArray(): " . (memory_get_usage() - $start_memory) . PHP_EOL; }
上記プログラムを実行したところ、次のような結果になりました。
Testing size: 5 Array(): 692 SplArray(): 532 Testing size: 10 Array(): 936 SplArray(): 604 Testing size: 20 Array(): 1708 SplArray(): 924 Testing size: 40 Array(): 3276 SplArray(): 1564 Testing size: 80 Array(): 6420 SplArray(): 2844 Testing size: 160 Array(): 12700 SplArray(): 5404 Testing size: 320 Array(): 25236 SplArray(): 10524 Testing size: 640 Array(): 50332 SplArray(): 20764 Testing size: 1280 Array(): 100496 SplArray(): 41244 Testing size: 2560 Array(): 200852 SplArray(): 82216 Testing size: 5120 Array(): 401596 SplArray(): 164144 Testing size: 10240 Array(): 803024 SplArray(): 327988
SplFixedArrayはPHP標準の配列に比べ、半分以下のメモリしか消費しません。これは速度差より断然インパクトのある差に感じられます。