찾다
백엔드 개발PHP 튜토리얼PHP5에서의 오류 처리 및 문제 위치 소개(코드 예)

이 글은 PHP5에서의 오류 처리 및 문제 위치에 대한 소개를 제공합니다(코드 예제). 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

PHP에서 E_ERROR 수준의 치명적인 런타임 오류가 발생했을 때 문제를 찾는 방법에 대해 이야기해 보겠습니다. 예를 들어 치명적인 오류: 허용된 크기의 메모리 메모리 오버플로입니다. 이런 종류의 오류가 발생하면 프로그램이 바로 종료됩니다. 오류가 보고된 특정 파일과 코드 줄 수를 나타내는 오류 로그가 PHP 오류 로그에 기록되며 다른 정보는 손실되지 않습니다. PHP7이라면 예외와 같은 오류를 잡을 수 있지만 PHP5에서는 그렇지 않습니다. Fatal error: Allowed memory size of内存溢出这种。当出现这种错误时会导致程序直接退出,PHP的error log中会记录一条错误日志说明报错的具体文件和代码行数,其它的任何信息都没有了。如果是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、开启core dump,如果生成code文件可以进行调试,但是发现code只有进程异常退出才会生成。像E_ERROR级别的错误不一定会生成code文件,内存溢出这种可能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 (
  '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()

回溯信息没有来源,尴尬了。猜测因为backtrace信息保存在内存中,当出现致命错误时会清空。没办法,把backtrace从外面传进来试试。再次修改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

일반적으로 생각되는 방법은 에러 리포트의 구체적인 코드를 살펴보는 것입니다. 에러 리포트 파일이 CommonReturn.class.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]
json_encode 라인에서 오류가 보고된 후 packData 메서드를 확인했습니다. 현재 문제를 어떻게 찾을 수 있나요?

장면 재현

  1. 자, 먼저 장면을 재현해 보겠습니다. 실제로 호출된 프로그램인 bug.php가 다음과 같다면

    rrreee

    bug.php를 실행하면 PHP 에러 로그에
  2. rrreee
  3. 이 기록됩니다. 재생에 성공하면 에러 로그가 나옵니다. 오류를 보고한 파일만 명시되어 있으며, 어떤 코드 줄에 대해서는 프로그램의 컨텍스트 스택 정보와 어떤 특정 비즈니스 로직이 호출되었는지 알 수 없으므로 오류를 찾아 수정하는 것이 불가능합니다. 간헐적으로 발생하는데 프론트엔드 업무에서 피드백이 없는 경우 문제 해결 방법.


    Solution

1. 어떤 사람들은 메모리 할당을 늘리기 위해 memory_limit를 수정하려고 생각했지만 이 방법은 증상을 치료할 뿐 근본 원인을 치료하지는 않습니다. 개발을 할 때에는 문제의 근본 원인을 찾아야 합니다.

    2.코드 파일이 생성되면 디버깅이 가능하지만, 프로세스가 비정상적으로 종료된 경우에만 코드가 생성되는 것으로 확인되었습니다. E_ERROR 수준의 오류는 반드시 코드 파일을 생성하지 않을 수도 있습니다. 메모리 오버플로 가능성은 PHP에서 내부적으로 처리됩니다.
  1. 3. PHP 종료 시 콜백 함수를 등록하기 위해 Register_shutdown_function을 사용하고, 마지막으로 발생한 오류가 발생하면 debug_print_backtrace를 사용하여 프로그램의 스택 정보를 얻으십시오.

  2. CommonReturn.class.php 파일을 다음과 같이 수정합니다.
rrreee
bug.php를 다시 실행하면 로그는 다음과 같습니다.

rrreee

트레이스백 정보에는 출처가 없어 당황스럽습니다. 역추적 정보는 메모리에 저장했다가 치명적인 오류가 발생하면 지워지기 때문인 것 같아요. 다른 방법은 없습니다. 외부에서 역추적을 전달해 보세요. CommonReturn.class.php를 다시 수정하세요. #🎜🎜#rrreee#🎜🎜#bug.php를 다시 실행하면 로그는 다음과 같습니다. #🎜🎜#rrreee#🎜🎜#bug.php의 13번째 줄에서 호출 소스를 성공적으로 찾았습니다. 최종 CommonReturn.class.php를 프로덕션 환경에 게시하고, 다시 오류가 발생하면 로그를 살펴보세요. 그러나 이 경우 packData를 호출하는 모든 프로그램은 추적 기능을 실행하므로 성능에 확실히 영향을 미칩니다. #🎜🎜##🎜🎜##🎜🎜#Summary#🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#사용된 Register_shutdown_function 함수에 주의해야 합니다. 여러 개의 다른 콜백을 등록할 수 있습니다. 하지만 특정 콜백 함수가 종료되면 나중에 등록된 콜백 함수는 모두 실행되지 않습니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜#debug_print_backtrace 역추적 정보를 얻는 첫 번째 함수에는 요청 매개변수가 포함됩니다. 두 번째 함수는 역추적 레코드 레이어 수를 저장하기 위한 요청 매개변수를 반환하지 않습니다. 약간의 돈이 필요하며 요청 매개변수가 큰 경우 이 함수를 호출하면 메모리가 직접 오버플로될 수 있습니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#가장 좋은 방법은 PHP7을 업그레이드하는 것인데, 예외와 같은 오류를 잡을 수 있습니다. . #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#

위 내용은 PHP5에서의 오류 처리 및 문제 위치 소개(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 segmentfault.에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php怎么实现几秒后执行一个函数php怎么实现几秒后执行一个函数Apr 24, 2022 pm 01:12 PM

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php字符串有没有下标php字符串有没有下标Apr 24, 2022 am 11:49 AM

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么读取字符串后几个字符php怎么读取字符串后几个字符Apr 22, 2022 pm 08:31 PM

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php怎么替换nbsp空格符php怎么替换nbsp空格符Apr 24, 2022 pm 02:55 PM

方法:1、用“str_replace("&nbsp;","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\&nbsp\;||\xc2\xa0)/","其他字符",$str)”语句。

php怎么查找字符串是第几位php怎么查找字符串是第几位Apr 22, 2022 pm 06:48 PM

查找方法:1、用strpos(),语法“strpos("字符串值","查找子串")+1”;2、用stripos(),语法“strpos("字符串值","查找子串")+1”。因为字符串是从0开始计数的,因此两个函数获取的位置需要进行加1处理。

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.