SplFixedArrayで固定長配列を扱う
SplFixedArrayは、サイズをあらかじめ固定した配列を扱うためのSPLクラスです。通常の配列より省メモリで、キーは0始まりの整数に限定されます。
普段PHPを書いていると配列のキーが文字列だったり飛び飛びの数値だったりするのが当たり前になっていて、SplFixedArrayの存在自体を忘れがちだと思います。ただ、数値インデックスで大量の要素を扱うような処理では、地味に効いてくる場面があります。
SplFixedArrayはどう使う?
使い方自体はシンプルです。コンストラクタにサイズを渡してインスタンス化し、あとは配列と同じように添字アクセスします。
$fixed = new SplFixedArray(5);
$fixed[0] = 'a';
$fixed[1] = 'b';
echo $fixed->getSize(); // 5
echo count($fixed); // 5(getSize()と同じ値)
$array = $fixed->toArray();
// ['a', 'b', null, null, null]
サイズを指定して確保しておくことで、通常の配列のようにキー追加のたびにハッシュテーブルを拡張する必要がなくなります。この「最初から箱の数が決まっている」という制約が、そのままメモリ効率の良さにつながっています。
通常の配列と何が違うのか
一番大きな違いはキーの扱いです。通常の配列は文字列キーも連想配列的な飛び飛びの数値キーも自由に使えますが、SplFixedArrayは0からサイズ未満までの整数キーしか受け付けません。範囲外のインデックスにアクセスするとRuntimeExceptionが投げられます。
$fixed = new SplFixedArray(3);
try {
$fixed[10] = 'x';
} catch (RuntimeException $e) {
echo $e->getMessage(); // Index invalid or out of range
}
通常の配列なら黙って要素が追加されるところで例外が飛んでくるので、意図しない範囲外アクセスに気づきやすいというのは地味なメリットです。逆に言うと、キーが動的に増減するような用途にはそもそも向いていません。
サイズを変えたいときはsetSize
「固定長」とはいえ、setSize()でサイズ自体を変更することはできます。縮めれば超過分は切り捨てられ、広げればnullで埋められます。
$fixed = new SplFixedArray(3);
$fixed[0] = 1;
$fixed[1] = 2;
$fixed[2] = 3;
$fixed->setSize(5);
// [1, 2, 3, null, null]
$fixed->setSize(2);
// [1, 2]
ただし、setSize()を頻繁に呼ぶくらいならSplFixedArrayを使う意味は薄れます。サイズが決め打ちできる場面、たとえば固定長のバッファや、件数が事前にわかっている集計結果を詰めるような場面で使うのが本来の使いどころだと思います。
PHPのバージョンによる違い
SplFixedArrayはPHP 8.0で内部の実装が変わっていて、それ以前はIteratorを実装していましたが、PHP 8ではIteratorAggregateに変わり、rewind()やcurrent()などの直接呼び出しはできなくなりgetIterator()経由になりました。foreachで回す分には意識しなくて大丈夫ですが、Iteratorとして直接扱っているコードが古いバージョンから移植されている場合は注意が必要です。
また、PHP 8.1からはJsonSerializableを実装するようになり、json_encode()に渡すとそのまま配列としてエンコードされます。以前のバージョンでは一度toArray()を挟む必要がありました。
まとめ
SplFixedArrayは、要素数が最初から決まっていて、かつ数値インデックスでアクセスするようなケースに向いたデータ構造です。通常の配列より省メモリで、範囲外アクセスも例外で検知できます。ただしキーの柔軟性を失う代わりの性能なので、普段使いの配列を全部置き換えるようなものではなく、大きな固定長データを扱う場面で選択肢に入れておく、くらいの距離感がちょうどいいのではないかと思います。
よくある質問
Q. SplFixedArrayは通常の配列よりどれくらい速いですか?
A. 速度差はケースによりますが、主なメリットは実行速度よりもメモリ使用量です。大量の数値インデックス要素を扱う場合にメモリ効率が良くなります。
Q. 文字列キーは使えますか?
A. 使えません。0以上サイズ未満の整数キーのみが有効で、それ以外はRuntimeExceptionになります。
Q. 通常の配列からSplFixedArrayに変換できますか?
A. SplFixedArray::fromArray()で通常の配列から生成できます。逆にtoArray()で通常の配列に戻せます。