例外処理
try / catch / throw — エラーを安全に扱う
エラーを if の戻り値ではなく 「例外オブジェクトを投げて、別の場所で拾う」 という構造で扱うトピック。
このトピックで身につくこと
try/catch/finallyを組み合わせてエラー処理を書けるthrow new Exception(...)で自分の関数から例外を投げられる- 例外の種類で処理を分岐できる
- カスタム例外クラスで「意味のあるエラー」を表現できる
- 「戻り値で
falseを返す」設計と「例外を投げる」設計を使い分けられる
前提知識の要点
このトピックは 「クラスが書ける」「関数が書ける」 の 2 点があれば始められる。さらに 1 つだけ重要な前提として 「Exception はクラスである」「new Exception() でインスタンスを作る」「throw は文 (式ではない)」 を押さえる。他のトピックの README を読み返さずに exception を単独で開始できる ように、以下を圧縮しておく。
1. クラスと new
<?php
class User {
public function __construct(public string $name) {}
public function greet(): string {
return "こんにちは、{$this->name}";
}
}
$u = new User("太郎");
echo $u->greet(); // => こんにちは、太郎このトピックで扱う Exception も「PHP に最初から組み込まれているクラスの 1 つ」というだけ。書き方は上と同じ。
2. 関数の引数・戻り値
function divide(int $a, int $b): int {
return intdiv($a, $b);
}このトピックでは「この関数は不正な入力のとき何を返す?」の答えとして「例外を投げる」を学ぶ。
3. これだけは新しく覚える: Exception はクラス・throw は文
// new でインスタンスを作る (普通のクラスと同じ)
$e = new Exception("失敗しました");
// throw でその例外を「投げる」(これ以降の行は実行されない)
throw $e;
// 1 行で書くのが普通
throw new Exception("失敗しました");重要なのは:
Exceptionはクラス。newでインスタンス化するthrowはそのインスタンスを投げる文。投げられた瞬間、関数の途中でも実行が止まる- 投げられた例外は、呼び出し元の
try { ... } catch { ... }で拾える - 誰も拾わないと
Uncaught Exceptionでプログラムが落ちる
継承は必須ではない
ch06 (カスタム例外) で extends Exception が出てくるが、「Exception クラスを継承して、独自の名前の例外を作る」というだけの使い方なので、class-advanced を完了していなくても ch06 直前の slide.md を読めば追いつける。
ここまで読めれば ch01 から始められる。
chapter 一覧
| chapter | 内容 | 学習目標 |
|---|---|---|
ch01-try-catch/ |
try / catch の基本 |
例外が起きうるコードを try { } catch { } で囲める |
ch02-throw/ |
throw で例外を投げる |
自分の関数から throw new Exception(...) できる |
ch03-exception-message/ |
例外メッセージの取り出し | $e->getMessage() でメッセージを取得できる |
ch04-multi-catch/ |
複数の例外を catch する | 例外の型ごとに処理を分けられる |
ch05-finally/ |
finally 句 |
成功/失敗に関わらず必ず通る処理を書ける |
ch06-custom-exception/ |
独自例外クラス | class XxxException extends Exception { } で意味のある例外を作れる |
ch07-rethrow/ |
再 throw (rethrow) | catch した例外を呼び出し元へ投げ直せる (概念のみ) |
ch08-validation-pattern/ |
バリデーション実践 | 入力検証で例外を活用する典型パターンを書ける |
合計 8 chapter / 7 drill (ch07 は概念説明のみ・drill なし) / 所要 3〜4 時間 程度。try / catch の動きは概念より「書いて動かす」が早い。
進め方
- 各 chapter の
slide.mdを読む (3〜5 分) drill/配下の問題を順番に解く (ch07 は読むだけ)- 採点:
php scripts/grade.php topics/exception/<chapter>/drill/<drill>/
つまづきポイント
| 症状 | 多くの原因 |
|---|---|
Uncaught Exception でプログラムが止まる |
throw した例外を誰も catch していない |
catch に入らない |
catch (DifferentException $e) のように違う型で捕まえようとしている。型階層を確認する |
try の途中で throw した後の行が実行された |
throw の後にコードを書いている。throw 以降の行は実行されないことを再確認 |
$e->getMessage() が空 |
new Exception() の引数にメッセージを渡し忘れ |
finally の中で return してしまった |
finally 内の return は try の戻り値より優先される。後始末以外は書かない |
カスタム例外で Class XxxException not found |
extends Exception を書き忘れ、または use し忘れ |
関連トピック
| トピック | 関係 |
|---|---|
| class | Exception もクラスの一種 (前提) |
| class-advanced | extends Exception でカスタム例外を作る |
| function | 不正な引数を throw で扱う設計が組み合わせ先 |
| array-multi | CSV パースなど、データ処理の失敗を例外で表現する |
トピックを並列で参照する全体地図は TOPICS_INDEX.md にある。
案件 (dojo_map.tsv) での参照
topic_slug chapter_dir
exception topics/exception/ch01-try-catch
exception topics/exception/ch02-throw
exception topics/exception/ch06-custom-exception
...
slug exception で参照可。10-exception / exception どちらの path でもアクセスできる (シンボリックリンク)。