1. 導入:なぜFatal Errorのログ取得が重要なのか
PHP開発において、try-catchブロックは例外処理の基本ですが、致命的なエラー(Fatal Error)が発生するとスクリプト自体が即座に停止するため、通常の例外処理では捕捉できません。本番環境で「画面が真っ白になる」といった事象が起きた際、適切なログが残っていないと原因特定に多大な時間を要します。本記事では、register_shutdown_functionを活用して、意図しない終了時にもエラー内容を確実に記録する方法を解説します。
2. 基礎知識:エラーハンドリングの仕組み
PHPには、スクリプトの実行が終了する直前に特定の関数を呼び出す仕組みがあります。それがregister_shutdown_function()です。この関数は、スクリプトが正常終了したか、あるいはFatal Errorで強制終了したかに関わらず実行されます。また、error_get_last()を使用することで、直前に発生したエラー情報を配列形式で取得できるため、これを組み合わせることで「事後ログ出力」が可能になります。
3. 実装・解決策
アプローチは非常にシンプルです。
1. スクリプトの先頭で終了時に呼び出す関数を登録する。
2. 登録した関数内でerror_get_last()を呼び出し、エラーの有無を確認する。
3. エラーがあればファイルやログサーバーへ書き出す。
この仕組みを導入することで、ユーザーに500エラーを表示する前に、開発者が原因を特定するための情報を残すことができます。
4. サンプルプログラム
以下は、Fatal Errorを捕捉してログファイルへ書き出す実用的なコードです。
/
register_shutdown_function(‘handleShutdown’);
// 存在しないクラスを呼び出し、意図的にFatal Errorを発生させる例
$test = new UndefinedClass();
/
- シャットダウン時にエラーをチェックする関数
/
function handleShutdown() {
// 最後に発生したエラーを取得
$error = error_get_last();
// エラーがない場合は終了
if (empty($error)) {
return;
}
// エラータイプに応じてログのラベルを決定
switch ($error[‘type’]) {
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
$type = “Fatal Error”;
break;
default:
$type = “Error”;
}
// ログメッセージの整形
$message = sprintf(
“[%s] %s: %s in %s on line %d” . PHP_EOL,
date(‘Y-m-d H:i:s’),
$type,
$error[‘message’],
$error[‘file’],
$error[‘line’]
);
// ログファイルへ追記(排他ロックをかけて書き込み)
file_put_contents(__DIR__ . ‘/error.log’, $message, FILE_APPEND | LOCK_EX);
}
?>
5. 応用・注意点
現場で運用する上で、以下の点に注意してください。
ログ出力先の権限設定: ログファイルを作成するディレクトリには、Webサーバー(www-dataやapacheユーザーなど)が書き込み権限を持っている必要があります。
メモリ枯渇時の挙動: E_ERRORの中でも「メモリ不足(Allowed memory size exhausted)」が原因の場合、ログを書き出すためのメモリすら残っていないことがあります。このリスクを軽減するため、スクリプト冒頭で一定量のメモリを確保(ダミー変数を割り当てるなど)しておくテクニックもあります。
ログの肥大化: 本番環境ではlogrotateなどを併用し、ログファイルが肥大化しすぎないようにローテーション管理を行うことが必須です。また、プロダクション環境ではエラー内容を直接画面に出力せず、今回のようなログ保存に徹するのがセキュリティ上の鉄則です。