- カテゴリ: helper
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN / コマンド:
report(Throwable $exception)(グローバル関数) - 関連: report_if / report_unless / logger / Log / throw_if
- 変更履歴: 特になし
要点(TL;DR)
- 目的:捕捉した例外を Laravel の例外ハンドラに渡してログ・通知・APMへ報告する
- 最小:
report($e); - 罠:
- レスポンスは返らない(画面制御は別途必要)
- 二重記録(
report()+Log::error()の併用)に注意 - ジョブ失敗は自動報告されるため、無闇な多重
report()は避ける
概要
report() は、app/Exceptions/Handler.php の設定にもとづいて例外を報告するための最短手段です。ログ出力、外部エラートラッカー(Sentry / Flare など)や通知への送信は、ハンドラ側の設定や各例外の report() / context() 実装に委ねられます。UIやHTTP応答の生成は行わないため、報告と応答は分けて設計します。
構文 / シグネチャ
// 例外をフレームワークの例外ハンドラに報告
function report(Throwable $exception): void;
// 条件付き報告(便利ヘルパ)
function report_if(bool $condition, Throwable $exception): void;
function report_unless(bool $condition, Throwable $exception): void;
- 引数(表) 引数 型 必須 既定値 説明 exception
Throwable✅ なし 報告したい例外インスタンス - 戻り値:
void(返り値なし) - 例外/副作用:通常は例外を投げません。ハンドラ設定に従ってログ書き込み・通知・APM送信が実行されます(外部I/O発生)。
使用例
最小例
<?php
use Throwable;
try {
riskyOperation();
} catch (Throwable $e) {
report($e); // ここでログ/APMに飛ぶ
return response()->json(['ok' => false], 200); // 画面制御は別途
}
実務例:外部API失敗を報告しつつフォールバック
<?php
namespace App\Services;
use App\Exceptions\PaymentFailed;
use Illuminate\Support\Facades\Cache;
use Throwable;
class PaymentService
{
public function charge(array $payload): bool
{
try {
// 決済API呼び出し...
return true;
} catch (Throwable $e) {
// 1) 文脈付き独自例外で報告
report(new PaymentFailed(
orderId: $payload['order_id'] ?? 0,
gateway: 'Stripe',
previous: $e,
));
// 2) フォールバック(たとえば予約状態に退避)
Cache::put("order:{$payload['order_id']}:pending", $payload, now()->addMinutes(10));
// 3) 画面や上位層には失敗可視化のみ
return false;
}
}
}
<?php
// 例外側でログ文脈を提供
namespace App\Exceptions;
use Exception;
class PaymentFailed extends Exception
{
public function __construct(
public int $orderId,
public string $gateway,
?\Throwable $previous = null
) {
parent::__construct('Payment failed', 0, $previous);
}
/** ログ/APMに追加される文脈 */
public function context(): array
{
return ['order_id' => $this->orderId, 'gateway' => $this->gateway];
}
}
よくある落とし穴・注意
- 画面は変わらない:
report()は「報告のみ」。HTTP応答は自分で返すか、例外を再throwしてフレームワークに任せる。 - 二重記録:
report()後にLog::error()を重ねると重複しやすい。どちらか一方に統一。 - dontReport リスト:
Handler::$dontReportに入っている例外は既定で報告されない。必要に応じて調整。 - ジョブ/コマンド:キューワーカーは失敗時に自動報告。catchして握り潰すなら明示的に
report()+リトライ設計を。 - 個人情報:
context()にPIIを直入れしない。マスキング運用を徹底。 - 条件付き:大量ループ内は
report_if()/report_unless()でサンプリングや条件報告を。
代替・関連APIとの比較
report()vsLog::error():report()は例外ハンドラ経由(dontReport尊重・外部連携一元化)。Log::error()は純粋にログ出力したいとき。report_if/report_unless:条件に応じて簡潔に書ける。throw_if/abort:フロー制御が主目的。報告はハンドラ側に委譲したいときに有効。- フレームワーク依存 / 純PHP代替:フレームワークに依存。純PHPなら
error_log()や独自ロガーで代替。 - コンテナ/グローバル状態:バインドされた
ExceptionHandlerとログ設定に依存(テストで差し替え可能)。
テスト例(Pest)
<?php
use Illuminate\Support\Facades\Log;
it('reports via exception report() method', function () {
Log::spy();
// report() メソッドを持つ匿名例外
$e = new class extends Exception {
public function report(): void
{
\Illuminate\Support\Facades\Log::info('reported');
}
};
report($e);
Log::shouldHaveReceived('info')->once()->with('reported');
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
Call to undefined function report() | Laravel外やブートストラップ不足 | Laravelアプリ内で実行。外部ならerror_log()等で代替 |
| 何も送信されない(Sentry等に出ない) | dontReport対象 / 連携未設定 | Handler::$dontReport見直し、連携パッケージとDSN設定を確認 |
| ログが重複する | report()とLog::error()の併用 / 再報告 | どちらかに統一。独自例外のreport()内重複も確認 |
| キューで大量通知 | ループ内で多重report() | report_if()で条件化 / サンプリング / バッチ化 |

