# ch06 — カスタム例外

Source: https://php-school.pages.dev/topics/exception/ch06-custom-exception/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: 例外処理
Level: L3

Reference (official): https://www.php.net/manual/ja/language.exceptions.php

## 本文

# ch06 — カスタム例外

## 概要

`throw new Exception("ユーザーが見つからない")` のようにメッセージで判別する書き方は手軽だが、catch 側が `getMessage()` の文字列を見て分岐するハメになって脆い。文言が少し変わるだけで分岐が壊れるし、IDE の補完も効かない。

PHP では `class UserNotFoundError extends Exception {}` のように **`Exception` を継承するだけ** で、自分のドメインに合った例外クラスを作れる。中身を実装する必要は無く、空クラスでも十分意味がある。なぜなら catch は **クラスの型で分岐** するので、`catch (UserNotFoundError $e)` と書いた瞬間に「これはユーザー未存在のときだけ来る」と読み手にも IDE にも伝わるからだ。

実用では「予約済みエラー」「在庫不足」「権限不足」のように、**アプリの世界 (ドメイン) が持つ概念に対して 1 クラスずつ** 例外を切るのが定石。標準の `RuntimeException` / `LogicException` のどちらを継承するかも設計上のヒントになる (実行時に外部要因で起きるなら Runtime、コードの論理ミスなら Logic)。この章のドリルは最小例で「クラスを作って投げて型で受ける」ループを通す。

## 学習目標

- `class MyError extends Exception {}` で独自の例外クラスを作れる
- 自作クラスを `throw` して、自作の型で `catch` できる
- ドメイン固有のエラーを **型で区別** できるようになる

## 所要時間

スライド 4 分 + ドリル 1 問 = **10 分**

## ドリル

| no | 内容 |
|---|---|
| 01 | `MyError extends Exception` を作って投げて受ける |

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 10 / Chapter 6
  目的: Exception を継承した独自例外クラスを作り、ドメイン固有のエラーを型で表す
  扱わない: rethrow (ch07) / カスタムにプロパティを追加する高度な使い方 / Throwable インターフェイス
  読み上げ時間目安: 3 分半〜4 分
-->

# カスタム例外

Lesson 10 / Chapter 6

---

## 標準の `Exception` だけだと区別がつかない

```php
<?php
try {
    if (在庫不足) throw new Exception("在庫不足");
    if (支払い失敗) throw new Exception("支払い失敗");
} catch (Exception $e) {
    // どっちの例外?
    // メッセージで判定するしかない…
}
```

- 全部 `Exception` だと、どの種類かを **文字列で判定** することになる
- 文字列マッチは壊れやすい

---

## `extends Exception` で自分の例外クラスを作る

```php
<?php
class StockError extends Exception {}
class PaymentError extends Exception {}
```

- ボディは空 (`{}`) でも OK
- `Exception` を継承するので、`getMessage()` などの機能はそのまま使える
- これだけで **新しい型** が手に入る

---

## 投げる: `throw new MyError(...)`

```php
<?php
function decrementStock(int $qty) {
    if ($qty <= 0) {
        throw new StockError("在庫がありません");
    }
}
```

- `throw new StockError("...")` で自作例外を投げる
- 使い方は標準 `Exception` と同じ

---

## 受ける: 型で振り分け

```php
<?php
try {
    decrementStock(0);
} catch (StockError $e) {
    echo "在庫エラー: " . $e->getMessage() . "\n";
} catch (PaymentError $e) {
    echo "支払いエラー: " . $e->getMessage() . "\n";
}
```

実行結果:

```
在庫エラー: 在庫がありません
```

- 型で区別できるので、メッセージマッチ不要
- ドメイン固有のエラーを **クラス階層** で表現できる

---

## このチャプターでできるようになること

✅ `class MyError extends Exception {}` で自作できる
✅ `throw new MyError(...)` で投げられる
✅ 自作の型で catch できる
✅ ドメイン固有エラーを型で区別できる

→ ドリルへ
