web-dev-qa-db-ja.com

通知/警告時にスクリプトの実行を停止する

PHP通知/警告時に実行をグローバルに停止することは可能ですか?

私たちは多くのサイトで開発サーバーを実行していますが、無視して先に進むのではなく、開発者にこれらの警告/通知を修正するように強制します(または少なくとも支援を求めます)。

36
Michael

はい、可能です。この質問は、PHPでエラーを処理する方法のより一般的な問題について述べています。 _set_error_handler_を使用してカスタムエラーハンドラを定義および登録する必要があります。docs PHPエラー。

私見では、任意のPHPエラーで例外をスローし、try/catchブロックを使用してプログラムフローを制御するのが最善ですが、この点について意見は異なります。

OPの定められた目標を達成するには、次のようなことをします。

_function errHandle($errNo, $errStr, $errFile, $errLine) {
    $msg = "$errStr in $errFile on line $errLine";
    if ($errNo == E_NOTICE || $errNo == E_WARNING) {
        throw new ErrorException($msg, $errNo);
    } else {
        echo $msg;
    }
}

set_error_handler('errHandle');
_

上記のコードは、_E_NOTICE_または_E_WARNING_が発生するたびにErrorExceptionをスローし、スクリプト出力を効果的に終了します(例外がキャッチされない場合)。 PHPエラーで例外をスローすることは、並列例外処理戦略( _set_exception_handler_ )と組み合わせるのが最適で、実稼働環境で正常に終了します。

上記の例は_@_エラー抑制演算子を尊重しないことに注意してください。これが重要な場合は、次のようにerror_reporting()関数を使用してチェックを追加するだけです。

_function errHandle($errNo, $errStr, $errFile, $errLine) {
    if (error_reporting() == 0) {
        // @ suppression used, don't worry about it
        return;
    }
    // handle error here
}
_
49
rdlowrey

PHP 5.3.0:

set_error_handler(
    function(int $nSeverity, string $strMessage, string $strFilePath, int $nLineNumber){
        if(error_reporting()!==0) // Not error suppression operator @
            throw new \ErrorException($strMessage, /*nExceptionCode*/ 0, $nSeverity, $strFilePath, $nLineNumber);
    },
    /*E_ALL*/ -1
);
6

php.iniファイル内でこれをグローバルに設定できます­ Docs

これを行うには、すべてのPHPプロセスで auto_prepend_fileディレクティブ­ Docs

auto_prepend_file "/full/path/to/a/prepend-file.php"

グローバルphp.iniファイル内でこれを行うと、プリペンドファイル内のコードが常に実行されます。次に、それを使用して、 すべてのエラーを例外に変換するグローバルエラーハンドラを登録できます。­ Docs

<?php
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");

この小さなスクリプトは、すべてのエラー/警告/通知などを ErrorException に変換します。

error_reporting iniディレクティブ­ Docs 、値はphp.iniファイルに記述されています。

例外をスローすることは非常に厳密です。プログラマーは警告とエラーに対処せざるを得ません。そうしないと、コードは機能しません。

おそらくこれはプログラマーにとっては多すぎて、社内では社会的に受け入れられないでしょう。代わりに、出力バッファリングを利用して、すべてのエラーをログに記録し、それらを出力の最後(または、より見やすくするために上部)に追加することもできます。

別の方法は、エラーと警告をログファイルに記録してから、そのファイルを別のプロセスで監視し、情報を集約することです。アプリケーションごとの警告数を表示するスコアボードを作成し、オフィスでこれを表示して、チームのパフォーマンスやそのような楽しみを誰もが確認できるようにすることができます。

私が言おうとしているのは、技術的な問題の次に、あなたが創造性を発揮し、実際に開発者から話をする必要がある社会的な問題です。警告とエラーを修正することが重要である理由と、それらからコーディングとスキルがどのように利益を得るかを明確にする必要があります。

6
hakre

開発環境にいる場合は、モジュールXdebugをインストールして、PHP iniファイルのどこかにxdebug.halt_level=E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICEを設定することを検討してください。開発者はxdebug.halt_levelをリセットできます。ハンドラーを元の値に復元できるため、set_error_handlerに基づく回答でも同じ問題が発生します。

3
user2066805

他のソリューションは、デフォルトのエラーロギングメカニズムをオーバーライドするカスタムエラーハンドラを実装しています。つまり、カスタムエラーハンドラーを設定すると、通知/警告はデフォルトの方法で印刷されなくなり、「通知/警告時にスクリプトの実行を停止する」以上のことを変更します。

ただし、メッセージをまだ印刷する方法が必要でした-私の場合PHP CLI-出力は別のプログラムによって解析されるため、メッセージを印刷したくありませんでした- 何らかの方法しかし、PHPが通常行うこととまったく同じ方法で。私はjustしたいstop the = PHP終了コードが!= 0のCLIプロセスは、通知/警告が出力された直後に、他に何も変更しないを実行します。

残念ながら、エラー処理全体を変更せずにスクリプトを終了するデフォルトの方法はないようです。そのため、PHPでデフォルトのエラーハンドラ(Cで実装)を再実装する必要がありました。

このため、PHPのソースコードのデフォルトのエラー印刷メカニズムを調べ、関連する部分をCからPHPに移植して、次のエラーハンドラを取得します。同様のものが必要です:

set_error_handler(
    function($errNo, $errStr, $errFile, $errLine) {
        $error_type_str = 'Error';
        // Source of the switch logic: default error handler in PHP's main.c
        switch ($errNo) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                $error_type_str = "Fatal error";
                break;
            case E_RECOVERABLE_ERROR:
                $error_type_str = "Recoverable fatal error";
                break;
            case E_WARNING:
            case E_CORE_WARNING:
            case E_COMPILE_WARNING:
            case E_USER_WARNING:
                $error_type_str = "Warning";
                break;
            case E_PARSE:
                $error_type_str = "Parse error";
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                $error_type_str = "Notice";
                break;
            case E_STRICT:
                $error_type_str = "Strict Standards";
                break;
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                $error_type_str = "Deprecated";
                break;
            default:
                $error_type_str = "Unknown error";
                break;
        }
        fwrite(STDERR, "PHP $error_type_str:  $errStr in $errFile on line $errLine\n");
        exit(1);
    },
    E_ALL
);
1
leemes