Hackの「例外」を飼いならせ:`<<__throws>>`で実現する型安全なエラーハンドリング
こんにちは。HHVMの深淵を覗き込み、Hackの型システムと日々格闘しているアーキテクトです。
Hackを触り始めた皆さんが、まず最初に「おや?」と首をかしげるポイント、それが例外処理です。PHPのノリで書いていると、「なぜか本番で例外が漏れて落ちる」「どこで何をキャッチすべきか分からない」という事態に陥りがちですよね。
JavaのChecked Exceptionに似ているようで、もっと柔軟で現代的なHackの「`<<__throws>>`アノテーション」。今回は、この機能をマスターして、あなたのコードを「落ちない堅牢な城」に変える方法を伝授します。
—
1. なぜ「例外」を型システムに組み込むのか?
一般的な言語では、例外は「突然発生する予期せぬ出来事」として扱われます。しかし、大規模なシステムにおいて「予期せぬ出来事」は、「設計上のミス」と同義です。
HackのStrict Modeでは、関数が何を投げ得るかを型レベルで明示できます。これにより、呼び出し側は「この関数を使うなら、この例外をハンドリングしないとコンパイルを通さないぞ」という強力な制約を課すことができます。これが、HHVMが提供する「型安全な実行環境」の真髄です。
—
2. `` の基本:例外を「契約」にする
まずは、単純な例を見てみましょう。
<<__EntryPoint>>
function main(): void {
try {
processData(10);
} catch (InvalidInputException $e) {
echo “不正な入力がありました: ” . $e->getMessage();
}
}
// <<__throws>> アノテーションで、この関数が何を投げるかを宣言します
<<__throws(InvalidInputException)>>
function processData(int $value): void {
if ($value < 0) {
throw new InvalidInputException("値は0以上である必要があります");
}
// 正常な処理...
}
class InvalidInputException extends Exception {}
このコードのポイント
- `<<__throws(ExceptionType)>>`: これを書くことで、Hackの型チェッカー(`hh_client`)は「この関数を使う場所では、必ずこの例外を考慮しなさい」と警告を発するようになります。
- コンパイル時の強制力: もし`processData`を呼び出す側で`try-catch`を忘れると、Hackは容赦なくエラーを吐いてビルドを止めます。これが、実行時エラーを激減させる秘訣です。
—
3. 陥りやすい罠:サブクラスと例外の伝播
初心者がよくつまずくのが、「例外の継承」と「アノテーションの範囲」です。
罠:例外の継承を忘れる
`<<__throws(Exception)>>` と書けば全ての例外をカバーできると思っていませんか? 確かに型としては合いますが、それでは「何が起きたか」を呼び出し側が判別できません。
// ダメな例:広すぎる例外定義はハンドリングを困難にします
<<__throws(Exception)>>
function fragileFunction(): void {
// …
}
推奨されるプラクティス:
例外は可能な限り具体的に定義しましょう。ドメイン固有の例外クラスを作成し、`<<__throws>>`で列挙することで、呼び出し側が「何に対処すべきか」が明確になります。
—
4. 現場で使える設計テクニック:`Result`型との使い分け
ここからが少し高度な話です。全てを例外で処理すべきでしょうか?
実は、HHVMのアーキテクトとしては、「予測可能なエラー」には例外を使わないという選択肢も提案します。
- 例外(`<<__throws>>`): システムの整合性が保てない、回復不可能な異常系(データベース接続断など)。
- `Result`型 (または `?T`): ビジネスロジック上の分岐(入力値エラー、該当なしなど)。
図解的イメージ:
- 例外: 「壁が崩れた!」(緊急停止して修理が必要)
- 戻り値: 「道が通行止めです」(別のルートを検討すればよい)
無理に例外を投げず、正常なフローとして扱えるものは型システムで表現する。これがHack上級者への第一歩です。
—
5. まとめ:型安全という名の「安心」を手に入れる
今回のポイントを整理しましょう。
1. `<<__throws>>`は契約: 関数と呼び出し側の間の「例外に関する約束事」です。
2. 型チェッカーを友にする: `hh_client`が警告を出すのは、あなたのコードが脆弱だからではなく、あなたを守るためです。
3. 例外を粒度細かく: 曖昧な`Exception`を投げず、具体的なエラークラスを定義しましょう。
Hackの型システムは、最初は厳しく感じるかもしれません。ですが、一度その「厳しさ」に慣れると、もう型のない世界には戻れなくなるはずです。自分の書いたコードが、コンパイルを通るたびに「安全であること」を証明してくれる。これこそが、Hackで開発する最大の喜びなのです。
ここをクリアできれば、あなたはもうHackの基礎を確実にマスターしたと言えます。自信を持って、次の実装に進んでくださいね!
—
何か不明点や、「もっと深いHHVMの内部構造の話が聞きたい」というリクエストがあれば、いつでも教えてください。エンジニア同士、とことん議論しましょう。