ホームページ  >  記事  >  バックエンド開発  >  PHP5 でのエラー処理と問題の場所の概要 (コード例)

PHP5 でのエラー処理と問題の場所の概要 (コード例)

不言
不言転載
2019-01-09 10:38:102586ブラウズ

この記事では、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[&#39;status&#39;] = $status;
        $res[&#39;data&#39;] = json_encode($params);
        return $res;
    }

}

json_encode 行でエラーが報告され、packData メソッドを確認しました。このメソッドを呼び出すプロジェクト クラスは多数あります。問題を特定するにはどうすればよいですか?

シーンの再現

まず、シーンを再現しましょう。実際に呼び出されるプログラム bug.php が次の場合

<?php

require_once &#39;./CommonReturn.class.php&#39;;

$res = ini_set(&#39;memory_limit&#39;, &#39;1m&#39;);

$res = [];
$char = str_repeat(&#39;x&#39;, 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([&#39;CommonReturn&#39;, &#39;handleFatal&#39;]);

        $res[&#39;status&#39;] = $status;
        $res[&#39;data&#39;] = json_encode($params);
        return $res;
    }

    /**
     * 错误处理
     */
    static protected function handleFatal()
    {
        $err = error_get_last();
        if ($err[&#39;type&#39;]) {
            ob_start();
            debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5);
            $trace = ob_get_clean();
            $log_cont = &#39;time=%s&#39; . PHP_EOL . &#39;error_get_last:%s&#39; . PHP_EOL . &#39;trace:%s&#39; . PHP_EOL;
            @file_put_contents(&#39;/tmp/debug_&#39; . __FUNCTION__ . &#39;.log&#39;, sprintf($log_cont, date(&#39;Y-m-d H:i:s&#39;), var_export($err, 1), $trace), FILE_APPEND);
        }

    }

}

bug.php を再度実行すると、ログは次のようになります。

error_get_last:array (
  &#39;type&#39; => 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([&#39;CommonReturn&#39;, &#39;handleFatal&#39;], $trace);

        $res[&#39;status&#39;] = $status;
        $res[&#39;data&#39;] = json_encode($params);
        return $res;
    }

    /**
     * 错误处理
     * @param $trace
     */
    static protected function handleFatal($trace)
    {
        $err = error_get_last();
        if ($err[&#39;type&#39;]) {
            $log_cont = &#39;time=%s&#39; . PHP_EOL . &#39;error_get_last:%s&#39; . PHP_EOL . &#39;trace:%s&#39; . PHP_EOL;
            @file_put_contents(&#39;/tmp/debug_&#39; . __FUNCTION__ . &#39;.log&#39;, sprintf($log_cont, date(&#39;Y-m-d H:i:s&#39;), var_export($err, 1), $trace), FILE_APPEND);
        }

    }

}

bug.php を再度実行すると、ログは次のようになります。

error_get_last:array (
  &#39;type&#39; => 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 を呼び出すすべてのプログラムがトレース関数を実行するため、パフォーマンスに確実に影響します。

概要

  1. 使用される register_shutdown_function 関数に注意する必要があります。複数の異なるコールバックを登録できますが、特定のコールバック関数が終了すると、後で登録されたコールバック関数は実行されません。

  2. debug_print_backtrace バックトレース情報を取得するこの関数には、最初にリクエスト パラメータが含まれており、2 番目にはバックトレース レコード レベルの数が含まれています。ここではリクエスト パラメータを返さないため、メモリを節約できます。 if リクエストパラメータが巨大な場合、この関数を呼び出すとメモリオーバーフローが発生する可能性があります。

  1. #最良の方法は、例外などのエラーをキャッチできる PHP7 をアップグレードすることです。


以上がPHP5 でのエラー処理と問題の場所の概要 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。