この記事では、PHP5 でのエラー処理と問題の場所の紹介 (コード例) を紹介します。これには一定の参考値があります。必要な友人は参照できます。お役に立てば幸いです。
PHP で E_ERROR レベルの致命的なランタイム エラーが発生した場合に、問題を特定する方法について説明します。たとえば、致命的エラー: 許容サイズのメモリが
メモリ オーバーフローしました。この種のエラーが発生すると、プログラムは直接終了し、エラーが報告された特定のファイルとコード行数を示すエラー ログが PHP のエラー ログに記録され、その他の情報は失われません。 PHP7であれば例外などのエラーをキャッチできますが、PHP5ではキャッチできません。
エラーレポートの具体的なコードを見る方法が一般的ですが、エラーファイルが CommonReturn.class.php の場合は以下のようになります。
<?php /** * 公共返回封装 * Class CommonReturn */ class CommonReturn { /** * 打包函数 * @param $params * @param int $status * * @return mixed */ static public function packData($params, $status = 0) { $res['status'] = $status; $res['data'] = json_encode($params); return $res; } }
json_encode 行でエラーが報告され、packData メソッドを確認しました。このメソッドを呼び出すプロジェクト クラスは多数あります。問題を特定するにはどうすればよいですか?
シーンの再現
まず、シーンを再現しましょう。実際に呼び出されるプログラム bug.php が次の場合
<?php require_once './CommonReturn.class.php'; $res = ini_set('memory_limit', '1m'); $res = []; $char = str_repeat('x', 999); for ($i = 0; $i < 900 ; $i++) { $res[] = $char; } $get_pack = CommonReturn::packData($res); // something else
bug.php を実行すると、PHP エラー ログには再現に成功したことが記録されます
[08-Jan-2019 11:22:52 Asia/Shanghai] PHP Fatal error: Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes) in /CommonReturn.class.php on line 20
エラー ログにはファイルの説明のみが表示されますおよびエラーが報告されたコード行。プログラムのコンテキスト スタック情報を知ることは不可能であり、ビジネス ロジックのどの部分が呼び出されるかもわからないため、エラーを特定して修正することはできません。時々発生し、フロントエンド ビジネスからのフィードバックがない場合のトラブルシューティング方法。
解決策のアイデア
1. メモリ割り当てを増やすためにmemory_limitを変更することを考えた人もいますが、この方法は症状を治療するものであり、根本的な原因を解決するものではありません。開発を行うときは、問題の根本原因を見つけなければなりません。
2. コアダンプをオンにし、コードファイルが生成されればデバッグ可能ですが、プロセスが異常終了した場合のみコードが生成されることが分かりました。 E_ERROR レベルのエラーは必ずしもコード ファイルを生成するとは限らず、メモリ オーバーフローの可能性は PHP によって内部的に処理されます。
3. register_shutdown_function で PHP 終了時のコールバック関数を登録し、error_get_last を呼び出し、最後に発生したエラーが取得できたら、debug_print_backtrace でプログラムのスタック情報を取得してみましょう。
CommonReturn.class.php ファイルを次のように変更します。
<?php /** * 公共返回封装 * Class CommonReturn */ class CommonReturn { /** * 打包函数 * @param $params * @param int $status * * @return mixed */ static public function packData($params, $status = 0) { register_shutdown_function(['CommonReturn', 'handleFatal']); $res['status'] = $status; $res['data'] = json_encode($params); return $res; } /** * 错误处理 */ static protected function handleFatal() { $err = error_get_last(); if ($err['type']) { ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); $trace = ob_get_clean(); $log_cont = 'time=%s' . PHP_EOL . 'error_get_last:%s' . PHP_EOL . 'trace:%s' . PHP_EOL; @file_put_contents('/tmp/debug_' . __FUNCTION__ . '.log', sprintf($log_cont, date('Y-m-d H:i:s'), var_export($err, 1), $trace), FILE_APPEND); } } }
bug.php を再度実行すると、ログは次のようになります。
error_get_last:array ( 'type' => 1, 'message' => 'Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes)', 'file' => '/CommonReturn.class.php', 'line' => 23, ) trace:#0 CommonReturn::handleFatal()
トレースバック情報にはソースがなく、恥ずかしいことです。バックトレース情報はメモリに保存されており、致命的なエラーが発生するとクリアされるためだと思います。仕方がないので、バックトレースを外側から渡してみます。 CommonReturn.class.php を再度変更します。
<?php /** * 公共返回封装 * Class CommonReturn */ class CommonReturn { /** * 打包函数 * @param $params * @param int $status * * @return mixed */ static public function packData($params, $status = 0) { ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); $trace = ob_get_clean(); register_shutdown_function(['CommonReturn', 'handleFatal'], $trace); $res['status'] = $status; $res['data'] = json_encode($params); return $res; } /** * 错误处理 * @param $trace */ static protected function handleFatal($trace) { $err = error_get_last(); if ($err['type']) { $log_cont = 'time=%s' . PHP_EOL . 'error_get_last:%s' . PHP_EOL . 'trace:%s' . PHP_EOL; @file_put_contents('/tmp/debug_' . __FUNCTION__ . '.log', sprintf($log_cont, date('Y-m-d H:i:s'), var_export($err, 1), $trace), FILE_APPEND); } } }
bug.php
を再度実行すると、ログは次のようになります。
error_get_last:array ( 'type' => 1, 'message' => 'Allowed memory size of 1048576 bytes exhausted (tried to allocate 525177 bytes)', 'file' => '/CommonReturn.class.php', 'line' => 26, ) trace:#0 CommonReturn::packData() called at [/bug.php:13]
呼び出しのソース (bug.php の 13 行目) を特定することに成功しました。最終的な CommonReturn.class.php を運用環境に公開し、エラーが再び発生したときにログを確認するだけです。ただし、この場合、packData を呼び出すすべてのプログラムがトレース関数を実行するため、パフォーマンスに確実に影響します。
概要
使用される register_shutdown_function 関数に注意する必要があります。複数の異なるコールバックを登録できますが、特定のコールバック関数が終了すると、後で登録されたコールバック関数は実行されません。
debug_print_backtrace バックトレース情報を取得するこの関数には、最初にリクエスト パラメータが含まれており、2 番目にはバックトレース レコード レベルの数が含まれています。ここではリクエスト パラメータを返さないため、メモリを節約できます。 if リクエストパラメータが巨大な場合、この関数を呼び出すとメモリオーバーフローが発生する可能性があります。
以上がPHP5 でのエラー処理と問題の場所の概要 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。