PHP配列という「負債」からの脱却:Hackコレクションがもたらす型安全とパフォーマンスの真実
PHPの配列(`array`)は、ある種のマジックボックスだ。リストであり、マップであり、セットでもある。しかし、その万能さは「予測不可能性」の代名詞でもある。型チェッカーから見れば、`array`は「中身が何であるか確定できないブラックボックス」だ。
我々がHackの`vec`、`dict`、`keyset`を導入したのは、単なる記法の刷新ではない。HHVMのJITエンジンが、型推論を通じてメモリレイアウトを最適化するための「契約書」を定義するためだ。
本稿では、PHPのレガシーな配列を捨て、Hackのコレクション型を使いこなすことで、堅牢なシステムを構築するための極意を伝授する。
—
1. なぜ「配列」を捨てるのか:HHVMの最適化戦略
PHPの配列は、実態としてハッシュテーブル(`Bucket`構造体)をベースにした複雑な実装だ。数値添字のリストであっても、内部ではハッシュ関数が走る可能性がある。
一方、Hackのコレクション型は異なる:
- `vec
` : 連続したメモリ領域に配置される。インデックスアクセスは$O(1)$であり、要素がすべて同じ型であれば、JITは配列の境界チェックを排除し、極めて高速なマシンコードを生成する。 - `dict
` : 型安全なハッシュマップ。キーと値の型が固定されているため、実行時に「キーが存在するか」という泥臭いチェックを最小限に抑えられる。 - `keyset
` : 値の重複を許さない集合。ハッシュセットとして最適化されており、存在判定のオーバーヘッドが極めて小さい。
これらを使うことは、「コードの意図をVMに明示し、実行時の型判定コストをゼロにする」という極めて合理的な選択なのだ。
—
2. 実践的設計パターン:バグを「コンパイル時」に殺す
現場のコードレビューでよく見かけるのは、「とりあえず`array`で受けて、中で`instanceof`や`is_array`で型ガードする」という設計だ。これはコードの複雑度を指数関数的に増大させる。
以下は、APIレスポンスの集約と加工を行う際の、最も保守性の高いパターンだ。
<<__EntryPoint>>
async function main(): Awaitable
// 1. APIから返却されるデータを型定義されたdictとして扱う
// 明示的な型指定により、データ構造の不整合をコンパイル時に検知できる
$data = vec[
shape(‘id’ => 1, ‘name’ => ‘Alice’),
shape(‘id’ => 2, ‘name’ => ‘Bob’),
];
// 2. フィルタリングと変換:高階関数を活用する
// PHPのforeachループで変数を汚染するより、パイプライン処理の方が宣言的で美しい
$names = vec($data)
|> Vec\map($, $item ==> $item[‘name’])
|> Vec\filter($, $name ==> Str\length($name) > 3);
// 3. 結果をkeysetで保持し、重複排除を自動化する
$uniqueNames = keyset($names);
\print_r($uniqueNames);
}
この設計のポイント
- `shape`の活用: `dict`の構造を固定することで、キーのタイポや欠落を型チェッカーが即座に指摘する。
- `Vec` / `Dict` 名前空間: 標準ライブラリの関数を活用せよ。これらは最適化されており、自前で書くループよりも高速かつ安全だ。
- イミュータブルな設計: データを直接書き換えるのではなく、変換結果を新しいコレクションとして生成する。これにより、非同期処理での競合や副作用を根絶できる。
—
3. パフォーマンスの罠を回避する:チーフアーキテクトからの助言
コレクション型への移行で、一つだけ注意してほしいことがある。「不必要な変換コスト」だ。
- 関数境界での型変換: `array`を受け取るAPIのラッパーを作る際、その境界で`vec()`や`dict()`への変換が必要になる。これは`O(n)`のコストがかかる。もしパフォーマンスが極めてシビアなホットパスであれば、境界を最小限にせよ。
- コレクションの結合: `vec`の結合(`+`演算子など)をループ内で繰り返すと、都度メモリ確保が発生し、パフォーマンスが劣化する。大量のデータを扱う場合は、事前に`Vec\fill`などで領域を確保するか、`Vec\concat`を一度だけ呼び出すように設計せよ。
—
結論:Hackの力は「制約」にある
型安全とは、単にバグを減らすための手段ではない。「思考の外部化」だ。
`vec`、`dict`、`keyset`を使用することは、あなたが「このデータ構造はこうあるべきだ」という意志を、コンパイラという冷徹な管理者に委ねることを意味する。一度この厳格な規律に慣れてしまえば、`array`という名の「何でもあり」の箱には二度と戻れなくなるはずだ。
あなたのコードがプロダクション環境で数百万リクエストを捌くとき、型安全という名の強固な基盤が、エンジニアであるあなたに真の平穏をもたらすだろう。
さあ、今すぐレガシーな`array`をリファクタリングし、型システムの加護を手に入れるのだ。