やあ。Hackの深淵へようこそ。
HHVMの型チェッカー(hh_client)の挙動を日々追いかけていると、多くの開発者が「実行時のバリデーション」に膨大なテストコードを費やしている事実に気づかされます。
「なぜ、その状態が許容されないのか」を、テストではなくコンパイル時(型チェック時)の制約として記述できたらどうだろう?
今日は、Hackの静的型システムを極限まで活用する「Phantom Types(幽霊型)」というテクニックを伝授します。これを使えば、ビジネスロジックの状態遷移を「型」という鉄壁のガードで守れるようになりますよ。
—
1. Phantom Typesとは何か?
Phantom Types(幽霊型)とは、「実行時には存在しない型パラメータを、コンパイル時のチェックのためだけに付与する」手法です。
Hackにおける `class Box
概念図:型による状態の封印
[ 状態A ] –(遷移)–> [ 状態B ]
| |
型A 型B
| |
+—–> [ 型チェッカーの監視 ] <-----+
↑ 不正な遷移をコンパイルエラーで弾く
---
2. 実践:注文ステータスの状態遷移を「型」で縛る
例えば、ECサイトの注文システムを考えてみましょう。`Draft`(下書き)から `Paid`(決済済み)へは遷移できるが、`Draft` からいきなり `Shipped`(発送済み)には飛べない。これを型で強制します。
コード例:状態遷移の型安全設計
<<__ConsistentConstruct>>
abstract class OrderState {}
final class Draft extends OrderState {}
final class Paid extends OrderState {}
final class Shipped extends OrderState {}
// T が Phantom Type となるクラス
final class Order
private function __construct(private int $id) {}
public static function createDraft(int $id): Order
return new Order($id);
}
// Draft から Paid への遷移のみ許可
public function pay(): Order
return new Order($this->id);
}
// Paid から Shipped への遷移のみ許可
public function ship(): Order
return new Order($this->id);
}
}
なぜこれが強力なのか?
この設計において、以下のコードを書いてみてください。
function process(Order
// $order->ship(); // ← ここで型チェッカーが叫びます!
// エラー: Order
}
そう、`ship()` は `Order
—
3. 初学者が陥りやすい罠と解決策
この手法を使い始めると、必ず一度は以下のエラーに遭遇します。
罠:型パラメータの不一致
function handle(Order
// 抽象クラス OrderState を指定しても、具体的な Order
}
解説:
Hackの型システムは「共変・反変」という概念を持っています。`Order
アドバイス:無理に複雑にしないこと
Phantom Typesは強力ですが、すべての状態管理に適用するのは「オーバースペック」です。
- 複雑なステートマシン:使うべき。
- 単なるフラグ管理:`bool` や `enum` で十分。
「型安全性を高める」ことは目的ではなく、「ビジネスロジックの不整合をゼロにする」ための手段であることを忘れないでくださいね。
—
最後に:Hackをマスターするということ
HHVMのアーキテクチャの根底には、「型はドキュメントではなく、実行可能な制約である」という思想があります。
Phantom Typesを使いこなせるようになれば、あなたのコードは「動かしてみないとバグが分からない」という不安から解放され、「コンパイルが通ったなら、そのロジックは正しい」という確信に変わります。
ここをクリアすれば、あなたはもうHackの初級者ではありません。より深く、より堅牢なシステム構築の入り口に立っています。もし不明な点があれば、いつでもHHVMの型チェッカーの挙動を深掘りしてみましょう。
さあ、次はどんな複雑なロジックを型で縛ってみますか?