throw_if — 条件が真なら例外を投げるヘルパ

helper
  • カテゴリ: helper
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: throw_if()(グローバル関数)
  • 関連: throw_unless / abort_if / abort_unless / rescue / report
  • 変更履歴: Laravel 5.5 で追加(以降継続)

要点(TL;DR)

  • 条件が true のときに例外を投げる簡潔記法。
  • throw_if($cond, MyException::class, 'msg')
  • 罠:HTTP用の中断は abort_if、例外の生成コストはクロージャで遅延させる、戻り値は基本null

概要

throw_ifif ($cond) { throw ... } の糖衣構文です。業務ロジックの前提チェック(早期リターン)で可読性を上げます。例外クラス名・インスタンス・あるいは例外を返すクロージャを渡せます。

構文 / シグネチャ

throw_if(
    bool $condition,
    \Throwable|string|callable $exception = RuntimeException::class,
    mixed ...$parameters
): void
  • 引数(表)
引数必須既定値説明
$conditionbooltrue のとき例外を投げる条件
$exceptionThrowable | string | callableRuntimeException::class例外インスタンス/例外クラス名/例外を返すクロージャ
...$parametersmixed例外クラス名を渡した場合のコンストラクタ引数
  • 戻り値void(例外を投げなければ実質 null
  • 例外/副作用:条件が真なら $exception に基づく例外を throw。他の副作用はなし。

使用例

最小例

<?php

use RuntimeException;

$user = null;

// 条件が真(ユーザー不在)なら例外
throw_if(is_null($user), RuntimeException::class, 'User not found');

// ここには到達しない(上で例外が投げられる)
echo "OK";

実務例(サービス層での前提チェック)

<?php

use App\Models\Order;
use App\Exceptions\PaymentNotAuthorized;
use Illuminate\Support\Facades\DB;

function capturePayment(int $orderId): void
{
    $order = Order::query()->with('payment')->find($orderId);

    // 例外の生成コストを遅延(必要時のみ new)
    throw_if(
        ! $order || ! $order->payment?->isAuthorized(),
        fn () => new PaymentNotAuthorized("Order #{$orderId} is not authorized.")
    );

    DB::transaction(function () use ($order) {
        $order->payment->capture();
        $order->markAsPaid();
    });
}

よくある落とし穴・注意

  • HTTP中断と混同しない:コントローラで 404/403 を返したい場合は abort_if を使う(HTTP Exception によるレスポンス)。
  • 例外生成のコスト:重いメッセージ整形や依存取得を伴う場合は クロージャで渡して遅延評価。
  • 戻り値に依存しない:式の値として使わない(例外を投げない限り null)。
  • 検証との役割分担:入力検証はバリデーション(FormRequest 等)。throw_if はアプリ内部の状態不整合の検出に。

代替・関連APIとの比較

  • if (...) { throw ... }(純PHP):最も汎用。throw_if は短く書けて意図が明確。
  • throw_unless($cond, ...):条件が false のときに投げる対称 API。読みやすい方を選択。
  • abort_if($cond, 403):HTTP レイヤの中断(ステータス+レスポンス)に最適。API/コントローラで使用。
  • rescue():例外を握りつぶしてデフォルト値を返す用途で逆方向。

テスト例(Pest)

<?php

use App\Exceptions\PaymentNotAuthorized;

it('throws when not authorized', function () {
    $fn = fn () => throw_if(true, PaymentNotAuthorized::class, 'NG');
    $fn();
})->throws(PaymentNotAuthorized::class, 'NG');

it('does nothing when condition is false', function () {
    expect(throw_if(false, RuntimeException::class, 'won\'t throw'))->toBeNull();
});

トラブルシュート(エラー別)

症状/エラー原因対処
ArgumentCountError例外クラス名を渡したがコンストラクタ引数が足りないクラスのシグネチャに合わせて ...$parameters を追加
望まない 500 が返るコントローラでビジネス条件の失敗を throw_if にしているAPI なら abort_if や適切な HTTP 例外へ置換
ログがノイズ化例外で制御フローを多用想定内(バリデーション等)は例外ではなく通常の分岐に寄せる

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする