【実務・中級編】【初心者向け】PHP配列から`vec`, `dict`, `keyset`への移行:型チェッカーが守るコレクションの整合性 – Hack言語 コア・静的型システムとHHVMのアーキテクチャ解析バイブル

【Hackを掌握する極限の知見】PHPの「なんでも屋配列」を捨てよ:`vec`, `dict`, `keyset` がもたらす静的安全性の極致

コードレビューの場で、未だにPHP時代の名残である `array` 型を見かけるたび、私はこう問うざるを得ない。
「君はその配列の中に、何が入っているのか本当に把握しているのか?」と。

PHPの配列(`array`)は、ハッシュマップであり、ベクターであり、リストでもあるという、極めてご都合主義的なデータ構造だ。キーに整数と文字列が混在し、値の型すらバラバラ。動的言語としてのプロトタイピングには最適だが、数百万ユーザーを抱えるプロダクション環境のコードベースにおいては、「いつ爆発するか分からない未処理の地雷原」に他ならない。

HHVM(HipHop Virtual Machine)のコアエンジン、そしてHackの厳格な静的型チェッカー(Typechecker)がなぜ存在するのか。それは、実行時エラーという名のギャンブルを終わらせるためだ。

今回は、PHPの雑多な配列から、Hackの真価である `vec`, `dict`, `keyset` への完全移行について、型チェッカーの挙動とメモリ管理の裏側を交えて徹底的に解説する。

—

1. なぜPHPの `array` は悪なのか? —— 型チェッカーの盲点とメモリ効率

PHPの `array` は、内部的にはHT(Hash Table)として実装されている。純粋なシーケンシャルなリストであっても、ハッシュのオーバーヘッドを背負い、メモリを無駄に消費する。さらに最悪なのは、「型が不確定であること」だ。

// 【アンチパターン】PHPスタイルの配列。型チェッカーは中身の型を追いきれない
function process_legacy_data(array $data): void {
// $data[0] は string なのか int なのか?
// 静的解析では完全にブラックボックス
$id = $data[‘id’] ?? 0;
}

このコードに対し、Hackの Strict Mode (`<>`) はこう叫ぶ。「型が不明確だ」と。
Hackのジェネリクスと専用コレクション(`vec`, `dict`, `keyset`)を導入することで、型チェッカーはコンパイル(正確には型チェック)の段階で型の不整合を完全に駆逐する。

3つの専用コレクションの正体

  • `vec`: 0から始まる連続した整数インデックスを持つ、順序付きリスト。PHPのリストとしての配列の完全な上位互換。メモリ効率が最適化されている。
  • `dict`: キーと値のペアを持つ連想配列。キーは `arraykey`(int または string)に限定される。
  • `keyset`: 重複を許さない値の集合。高速なメンバーシップテスト(存在確認)に特化。

—

2. 実務で即効性のある移行パターン:プロダクションコード設計

では、実際のAPI連携やドメインロジックにおいて、どのように `vec` や `dict` へ移行すべきか。
ここでは、外部の非同期APIから受け取ったユーザーデータをパースし、安全に処理する堅牢な設計パターンを示す。

綺麗で保守性の高いプロダクションコード例

<>

namespace App\Core;

/

  • ユーザー情報のデータ構造を表現する形状(Shape)
  • キーの存在と値の型を静的に保証する

/
type UserShape = shape(
‘id’ => int,
‘name’ => string,
‘roles’ => vec,
);

class UserDataManager {

/

  • 外部APIからのレスポンス(配列)を、厳格な dict と vec に変換する
  • @param array $raw_response
  • @return dict

/
public static function parseAndValidateUsers(array $raw_response): dict {
// dictBuilder を使って効率的に構築
$builder = dict[];

// $raw_response[‘users’] が存在し、かつ配列であることを担保前提とする
// 実際にはここで Shapes::idx や型ガードを入念に行う
$users_array = idx($raw_response, ‘users’);
if (!is_array($users_array)) {
throw new \InvalidArgumentException(‘Invalid payload structure: users missing.’);
}

foreach ($users_array as $userData) {
if (!is_array($userData)) {
continue;
}

// 型アサーションまたは厳密なキャストを経て vec/dict へ落とし込む
$id = idx($userData, ‘id’);
$name = idx($userData, ‘name’);
$roles = idx($userData, ‘roles’);

if (is_int($id) && is_string($name) && is_array($roles)) {
// ロール配列も string の vec へ強制変換
$safe_roles = vec[];
foreach ($roles as $role) {
if (is_string($role)) {
$safe_roles[] = $role;
}
}

$shape: UserShape = shape(
‘id’ => $id,
‘name’ => $name,
‘roles’ => $safe_roles,
);

$builder[$id] = $shape;
}
}

// 構築された dict は不変(immutable)に近い振る舞いを提供し、型安全性が保証される
return $builder;
}

/

  • 管理者権限を持つユーザーのIDを高速に抽出する
  • keyset を用いることで重複排除と O(1) に近い検索性を担保

/
public static function getAdminIds(dict $users): keyset {
$admin_ids = keyset[];

foreach ($users as $id => $user) {
// vec の関数型操作(C# LINQ風のパイプライン)を使っても美しい
if (\C\contains($user[‘roles’], ‘ADMIN’)) {
$admin_ids[] = $id;
}
}

return $admin_ids;
}
}

—

3. コードレビューの視点:なぜこの設計が優れているのか

上記のコードが、なぜシニアエンジニアのコードレビューを難なく通過し、ジュニアのコードを根底から覆すのか。その理由は3点ある。

1. `shape` 型とのシナジー
`dict` のキー構造が曖昧である場合、`shape` を組み合わせることで、ドキュメント要らずの「自己文書化コード」が完成する。型チェッカーは `’id’` というキーが存在しないコードをコンパイルエラーとして弾く。
2. 境界でのバリデーション(Defensive Boundary)
外部世界(HTTPリクエストやJSONデコード結果)は常に汚染されている。PHPの `array` から受け取った瞬間に、型ガードを通過させて `vec` や `dict` に封じ込める。この「境界線の防衛」こそが、アプリケーション全体をクリーンに保つ秘訣だ。
3. HHVMのネイティブ最適化の恩恵
`vec`, `dict`, `keyset` はHHVMのJITコンパイラにとって非常に扱いやすいデータ構造である。内部的なメモリレイアウトが連続しているため、キャッシュヒット率が向上し、CPUパイプラインを効率的に利用できる。

—

4. 移行時の注意点とパフォーマンスの罠

「じゃあ、今日から既存のコードの `array` を全部 `vec` に書き換えよう」と思ったそこのあなた。少し待ってほしい。型チェッカーの網をくぐらせる際、以下の罠にハマることがある。

  • JSONデコードの戻り値

`json_decode($json, true)` は依然として `mixed`(実質的にはPHPの配列)を返す。これを直接 `vec` や `dict` に代入することはできない。必ず明示的なキャスト、あるいは安全なマッピング関数を挟むこと。

  • 過剰な変換コスト

ループの都度 `array` から `vec` へキャストするような処理をホットパス(高頻度で実行されるコード片)に書くと、変換オーバーヘッドがボトルネックになる。データ境界(入出力の境界)でのみ変換を行い、ドメイン層の内部は常に `vec`/サイズの保証された `dict` で貫通させるのが正しいアーキテクチャである。

—

結び:型チェッカーは敵ではなく、最強の相棒である

Hackの型チェッカーは、開発者の足を縛る足枷ではない。あなたの代わりに夜間テストを走り続け、うっかりミスによる本番障害を未然に防ぎ続けてくれる「不眠不休の最高責任アーキテクト」だ。

PHPの曖昧な配列という魔物を断ち切り、`vec`, `dict`, `keyset` による厳格な秩序をコードベースにもたらすこと。それこそが、Hackを使いこなすエンジニアの特権であり、義務なのである。

さあ、IDEを開き、あなたのコードベースにある `array` の総数を数えてみるといい。そして、一つ残らず、あるべき型へと昇華させたまえ。

タイトルとURLをコピーしました