PHPの負債を断つ:`array`という名の「不確定性」をHSLの厳格な構造体へ再編する
PHPの`array`は、かつては柔軟性の象徴であったが、現在の我々にとっては「ランタイムの爆弾」に他ならない。メモリレイアウトの予測不可能性、型推論の破壊、そして計算量の隠蔽。これらはスケーラブルなシステムを構築する上での最大の敵だ。
Hackにおいて、我々は`array`を解体し、`dict`と`keyset`という専門化されたデータ構造へと移行させた。これは単なるAPIの変更ではない。HHVMの仮想マシンレベルでの最適化を最大化し、型チェッカーが静的に正当性を保証するための「必然」である。
本稿では、この移行の背後にあるアーキテクチャの真実を解説する。
—
1. `array`の罪:なぜPHPの連想配列は計算量を裏切るのか
PHPの`array`は、ハッシュテーブルと連結リストのハイブリッドであり、非常に複雑なメモリ構造を持つ。HHVMのJITコンパイラから見れば、`array`は「中身が何であるか確定できないブラックボックス」だ。
- 型情報の欠如: `array`は値の型を保持しない。そのため、各要素へのアクセスごとに型チェックのオーバーヘッドが発生する。
- 二重の責務: `array`は「連想配列(Map)」と「集合(Set)」の両方を同じ内部構造で扱う。これが意味するのは、意図しない衝突や、メモリ配置の断片化である。
- 不確定なコスト: 集合として使っているつもりの`array`に対し、ランタイムは常にハッシュ計算を強いる。これは、本来`keyset`であれば最適化可能なパスを無効化する。
2. `dict`と`keyset`による責務の分離
HSL(Hack Standard Library)への移行の核心は、「計算の性質に基づいたデータ構造の選択」にある。
dict: 決定論的なマッピング
`dict`は、キーと値の厳格なペアリングを強制する。HHVMの内部では、`dict`はより最適化されたハッシュテーブルとして扱われ、特定の型シグネチャを保証する。
// 悪い例: PHP的なarrayの使用
$map = [‘user_id’ => 101, ‘role’ => ‘admin’];
// 良い例: dictによる型安全な定義
// HHVMはこれを単一のメモリブロックとして効率的に割り当てる
dict
‘user_id’ => 101,
‘role’ => ‘admin’,
];
keyset: 集合演算の最適化
`keyset`は一意な値の集合に特化している。特筆すべきは、値がハッシュ値のキャッシュを保持することだ。重複チェックがO(1)で完了し、かつメモリ消費も大幅に削減される。
// 集合としての運用では、keysetが最強のパフォーマンスを発揮する
// array_unique()のようなランタイムの重いスキャンを排除できる
keyset
3. コンパイラとメモリ管理の深淵
HHVMのアーキテクチャにおいて、`dict`と`keyset`への移行がパフォーマンスを劇的に改善する理由は「型情報とメモリレイアウトの一致」にある。
1. 型の特化 (Type Specialization):
`dict
2. コピー・オン・ライトの最適化:
Hackのデータ構造は不変性(Immutability)を重視する設計になっている。`dict`や`keyset`の変更操作は、HHVMの参照カウント管理と相性が良く、不必要なメモリコピーを極限まで抑制している。
4. 実戦的なマイグレーション戦略:段階的リファクタリング
既存のPHPコードベースを移行する際、すべてを一度に書き換えるのは自殺行為だ。以下のステップで進めるべきである。
1. 境界の定義: 外部APIやデータベースからの入力を `array` から `dict`/`keyset` に変換する「境界層(Boundary Layer)」を設ける。
2. 型アノテーションの強制: `hhvm.hack.lang.check_array_literals` を有効にし、型なし配列の利用を禁止する。
3. 計算量の可視化: 既存の `in_array()` を `keyset` の `contains()` に置換するだけで、大規模なデータセットにおける検索コストは劇的に改善する。
移行のチェックリスト
- [ ] `array_merge` などの副作用のある関数を、HSLの不変な操作関数(`dict\merge`等)に置き換えたか?
- [ ] `array` を引数に取る古い関数を、`KeyedContainer` や具体的な `dict` 型に書き換えたか?
- [ ] 集合演算(`array_diff`, `array_intersect`)を `keyset` の演算に移行したか?
結論:コードの「重量」を削ぎ落とせ
Hack言語における型システムは、単なるバグ除けではない。それは、計算機に対する命令の精度そのものである。`array`という曖昧な構造を捨て、`dict`と`keyset`という明確な意図をコードに記述すること。それが、シニアエンジニアとして、またアーキテクトとして、システムの「重さ」を制御し、極限のパフォーマンスを引き出す唯一の道だ。
コードは書くものではない。設計するものである。そして、その設計図はメモリの深淵まで到達していなければならない。