Skip to content

Instantly share code, notes, and snippets.

@uzulla
Last active September 21, 2025 03:21
Show Gist options
  • Save uzulla/6f7465472b4a4cd5be30d8993c927ed9 to your computer and use it in GitHub Desktop.
Save uzulla/6f7465472b4a4cd5be30d8993c927ed9 to your computer and use it in GitHub Desktop.
Filtered PHP Error Logger that Skips Deprecation/Strict Notices and PHPStan Stack Frames
<?php
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
// 一旦、以下エラーならスキップする(量が多いので)
if (in_array($errno, [
E_DEPRECATED,
E_STRICT,
], true)) {
return false;
}
$types = [
E_WARNING => 'E_WARNING',
E_ERROR => 'E_ERROR',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE',
E_STRICT => 'E_STRICT',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
E_DEPRECATED => 'E_DEPRECATED',
E_USER_DEPRECATED => 'E_USER_DEPRECATED',
];
$type = $types[$errno] ?? "Unknown Error";
$err_type = $types[$errno] ?? "Unknown Error";
error_log("{$err_type} {$errfile}:{$errline}, $errstr");
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
foreach ($trace as $i => $frame) {
if (isset($frame['file']) && strpos($frame['file'], 'phpstan.phar') !== false) {
error_log("Skip phpstan stack trace\n");
break; // 以降はphpstan.pharなのでスキップ
}
$file = $frame['file'] ?? '[internal function]';
$line = $frame['line'] ?? '';
$func = $frame['function'] ?? '';
error_log("#{$i} {$file}({$line}): {$func}()");
}
// true : エラーが ユーザー定義ハンドラで処理済み とみなされ、PHP の内部エラーハンドラは呼び出されません。
// false (または null): ユーザー定義ハンドラは 処理を放棄 し、PHP のデフォルトエラーハンドラが続行します。
return false;
});

概要

このスクリプトは PHP のカスタムエラーハンドラset_error_handler で登録し、特定のエラーはスキップしつつ、残りのエラー情報をログに出力します。


主な処理の流れ

  1. ハンドラ登録

    set_error_handler(function ($errno, $errstr, $errfile, $errline) { … });

    set_error_handler に無名関数を渡すことで、PHP がエラーを検出したときにこの関数が呼び出されます。

  2. スキップ対象エラーの判定

    if (in_array($errno, [E_DEPRECATED, E_STRICT], true)) {
        return false;
    }
    • E_DEPRECATED(非推奨機能の使用)と E_STRICT(コードの厳密性に関する警告)は大量に出ることがあるため、ハンドラは何もしないfalse を返す)ことで PHP のデフォルトハンドラに処理を委ね、実質的に無視します。
  3. エラー種別名の取得

    $types = [ … ];               // エラー定数 → 文字列名 のマッピング
    $type = $types[$errno] ?? "Unknown Error";
    $err_type = $types[$errno] ?? "Unknown Error";

    エラー番号 $errno を人が読める文字列に変換し、ログ出力に使用します。

  4. エラーメッセージのログ出力

    error_log("{$err_type} {$errfile}:{$errline}, $errstr");

    エラー種別、発生ファイル、行番号、エラーメッセージを1行で記録します。

  5. スタックトレースの取得と加工

    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    foreach ($trace as $i => $frame) {
        if (isset($frame['file']) && strpos($frame['file'], 'phpstan.phar') !== false) {
            error_log("Skip phpstan stack trace\n");
            break;
        }
        $file = $frame['file'] ?? '[internal function]';
        $line = $frame['line'] ?? '';
        $func = $frame['function'] ?? '';
        error_log("#{$i} {$file}({$line}): {$func}()");
    }
    • debug_backtrace で現在の呼び出しスタックを取得(引数は除外)。
    • 各フレームを走査し、phpstan.phar が含まれるフレーム が現れたらそれ以降のトレースは不要として break
      → PHPStan(静的解析ツール)の内部呼び出しはノイズになるため除外。
    • それ以外は file(line): function() 形式でログに出力。
  6. ハンドラの戻り値

    return false;
    • false(または null)を返すと、ユーザー定義ハンドラは処理を放棄し、PHP のデフォルトエラーハンドラが続行します。
    • ここでは常に false を返すので、エラーはログに残りつつ、通常の PHP エラーメッセージも表示されます。

使いどころと効果

シナリオ 目的 効果
大規模テストや CI 環境 E_DEPRECATEDE_STRICT が大量に出るが無視したい ノイズが減り、重要な警告だけが目に入る
デバッグ時にスタックトレースが必要 エラー発生箇所と呼び出し経路を把握したい error_log に分かりやすいトレースが出力
静的解析ツール(PHPStan)と併用 PHPStan の内部スタックが混入しないようにしたい phpstan.phar 以降のフレームを除外し、ログがクリーンになる

注意点

  • return false により PHP の標準エラーハンドラが実行されるので、画面上にもエラーメッセージが出ます。完全に抑制したい場合は return true に変更してください。
  • error_log の出力先は PHP の設定 (error_log ディレクティブ) に依存します。環境に合わせて適切に設定してください。
  • E_DEPRECATEDE_STRICT をスキップすると、将来の互換性問題を見逃すリスクがあります。開発段階でだけ有効にし、リリース前に除外を外すことが推奨されます。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment