【入門編】【中級者向け】Hackにおける例外処理の型定義:throwsアノテーションによる呼び出し側の安全性確保 – Hack言語 コア・静的型システムとHHVMのアーキテクチャ解析バイブル

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の内部構造の話が聞きたい」というリクエストがあれば、いつでも教えてください。エンジニア同士、とことん議論しましょう。

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