文档章节

关于PHP自动捕捉处理错误和异常的尝试

o
 osc_a22drz29
发布于 2019/03/21 17:40
字数 1895
阅读 10
收藏 0

精选30+云产品,助力企业轻松上云!>>>

  之所以想着做错误和异常的自动处理是因为:

    用的公司自己的框架写API,没有异常和错误相关功能,

    而每次操作都进行try...catch,有点繁琐不说,感觉还很鸡肋,即使我catch到了,还是得写代码进行处理,哪怕封装了一个方法进行处理也还是繁琐,

    这种情况应该是程序自动进行处理,不该是这样弱智的人工try...catch,然后处理

    以及其他同事写代码时并不能严格的进行try...catch

    于是乎,想自己设计一个自动捕获并处理错误和异常的功能。

  发现了一篇深度好文:https://www.cnblogs.com/zyf-zhaoyafei/p/6928149.html

     理解了PHP中自带的  register_shutdown_function,set_error_handler,set_exception_handler这三个函数

  通过这三个函数我们可以实现PHP 自动捕获异常和错误。PHP5也不支持ERROR的捕获,只能try...catch (Exception) 

  三个函数必须理解,如果你想实现该功能,希望你可以先做个小demo体验下三个函数的神奇之处

  这三个函数需要你写在框架的生命周期比较靠前的地方,如果不知道写哪里,请写在入口文件中,或者在入口文件require一下(下面的源码可以直接require使用

  因为如果写到其他文件中,而碰巧该文件有错误或者异常,那么这三个函数就不发生作用了,而入口文件我们都可以确保正确

  正文:

      首先介绍set_error_handler这个函数,这个函数用于捕获低级别的错误,该函数只能捕获系统产生的一些Warning、Notice级别的错误,并调用一个用户自定义的错误处理函数。

    比如在入口文件写入  set_error_handler('low_level_error'),并且我们建立了low_level_error 自定义方法来进行日志的记录 。

    当发生Warning、Notice级别的错误时,系统会自动调用low_level_error方法,四个参数"type"、 "message"、"file" 和 "line"也是系统传过来的,可以直接使用。

    注意:使用此函数后  error_reporting ( E_ALL )  无法提示warning和notice级别的警告, 如果本地开发,最好关闭此函数,在生产环境才使用;  使用 其它两个函数 时错误提示信息不受影响

 

    可以使用下面源码中的单个方法进行测试, 只需echo $str; exit; 就好

      第二个函数 register_shutdown_function, 这个函数与第一个函数搭配使用,可以捕捉到Fatal Error、Parse Error等高级别会让程序中止的错误,

    这个方法是PHP脚本执行结束前最后一个调用的函数,比如脚本错误、die()、exit、异常、正常结束都会调用。这个方法没有接受参数,所以需要借助error_get_last() ,error_get_last函数可以获取到

    系统最近发生的一个错误,同样包含  "type"、 "message"、"file" 和 "line"四个字段,需要注意的是 本函数捕捉到的 (2,8,32,128,512,1024,2048,8192)等错误都是警告级别的,自己酌情处理。

 

      第三个函数set_exception_handler, 这个函数可以捕获 没有用try/catch块来捕获的异常,并且在回调函数调用后异常会中止(这个我没有试,因为我捕捉异常后直接返回给前端错误code码了)。

  思路:通过set_error_handler 和 register_shutdown_function 两个函数可以捕捉到所有的错误,通过set_exception_handler 捕捉所有未处理的异常,这样程序中所有的错误和异常就被我们捕捉到了,

    接下来,我们可以通过自定义函数对它们进行操作,由于我的业务是直接向前端输出,因此只是记录相关日志后直接echo并退出,大家可以在自定义函数内自己决定做什么处理。

    还可以在两个自定义的错误处理函数中再抛出异常,由自定义的异常处理类统一处理,这也是一个不错的思路,大家可以尝试下。

  最后:

    下面是相关的代码,供大家参考和测试。

 

<?php
/**引入本文件后,PHP会自动处理错误和异常, php版本5.6, php7+版本需要小调整,运行时根据提示调整即可
 * 本方法直接捕捉错误并记录日志,如有兴趣,可以捕捉到错误后再次抛出异常,将错误转为异常后,由set_exception_handler统一进行处理
 * User: LiZheng  271648298@qq.com
 * Date: 2019/3/21
 */
register_shutdown_function('high_level_error');   //使用了register_shutdown_function 后,当程序遇见一些致命错误时会自动调用函数 high_level_error
set_error_handler('low_level_error');        //使用了set_error_handler 后,当程序遇见Notice 和Warning错误时会自动调用函数 low_level_error
set_exception_handler('exception_log'); //使用了set_exception_handler后,当遇到所有的未捕获的异常时会自动调用函数 exception_log
/**
 * 该方法只能捕获系统产生的一些Warning、Notice级别的错误
 * @param $type
 * @param $message
 * @param $file
 * @param $line
 * User: LiZheng  271648298@qq.com
 * Date: 2019/3/21
 */
function low_level_error($type, $message, $file, $line)
{
    $time = date('Y-m-d H:i:s');
    //拼接要记录成日志的信息
    $str = "\n ".$time.' set_error_handler: ' . exception_self::get_type($type) . ':' . $message . ' in ' . $file . ' on ' . $line . ' line .';
    $str = addslashes($str);
    //记录日志    error_log是PHP自带函数,记录到指定位置,详情见官网
    error_log($str,3,ROOT_DIR."/runtime/logs/php_error.log");  //ROOT_DIR为项目根目录
    //对于notice和warning 级别的错误,只进行记录而不会终止程序(但在本地开发时希望提示,可以通过if语句判断)
    //echo json_encode(array('code'=>“ERR_ERROR”, 'msg'=>$time, 'data'=>array()), true);exit;
}

/**
 * 捕捉一些致命错误
 * User: LiZheng  271648298@qq.com
 * Date: 2019/3/21
 */
function high_level_error()
{
    //error_get_last() 获取最近一条发生的错误,包含"type"、 "message"、"file" 和 "line"
    if ($error = error_get_last()) {
        $time = date('Y-m-d H:i:s');
        //拼接要记录成日志的信息
        $str = "\n ".$time.' register_shutdown_function: Type:' . exception_self::get_type($error['type']) . ' Msg: ' . $error['message'] . ' in ' . $error['file'] . ' on line ' . $error['line'];
        $str =  addslashes($str);
        //记录日志    error_log是PHP自带函数,记录到指定位置,还可以发送邮件以及其他操作
        error_log($str,3,ROOT_DIR."/runtime/logs/php_error.log");   //ROOT_DIR为项目根目录
        //直接输出接口的返回信息, 给前端一个错误码code, msg返回时间用于方便查找日志
        //echo json_encode(array('code'=>“ERR_ERROR”, 'msg'=>$time, 'data'=>array()), true);exit;
        if(in_array($error['type'], array(2,8,32,128,512,1024,2048,8192)))//本条件中的错误均为非致命错误,  8192 错误是弃用提示
        {
//            if(APP_ENV == 'LOCAL')  //这里可以对本地开发环境时进行不同的处理
//            {
//                header('Content-Type: text/html; charset=utf-8');
//                echo $str."\n";
//            }
        }else
        {
//            if(APP_ENV == 'LOCAL')
//            {
//                header('Content-Type: text/html; charset=utf-8');
//                echo $str."\n";
//            }
            //直接输出接口的返回信息, 给前端一个错误码code, msg返回时间用于方便查找日志
            echo json_encode(array('code'=>ERR_ERROR, 'msg'=>$time, 'data'=>array()), true);exit;
        }
    }
}

/**
 * 捕捉异常
 * @param $exception
 * User: LiZheng  271648298@qq.com
 * Date: 2019/3/21
 */
function exception_log($exception)
{
    $time = date('Y-m-d H:i:s');
    //拼接要记录成日志的信息
    $str = "\n ".$time." set_exception_handler: Exception: ". $exception->getMessage()." in ".$exception->getFile()." on line ". $exception->getLine();
    $str =  addslashes($str);
    //记录日志
    error_log($str,3,ROOT_DIR."/runtime/logs/php_error.log");
    //输出信息
    echo json_encode(array('code'=>“ERR_EXCEPTION”, 'msg'=>$time, 'data'=>array()), true);exit;
}

/**
 * Class error_handler
 * Create on 2019/3/21 14:15
 * User: LiZheng  271648298@qq.com
 * Date: 2019/3/21
 */
class exception_self extends Exception
{
    /**
     * 构造函数
     * @param string $message
     * @param string $code
     */
    public function __construct($message=null, $code=null)
    {
        parent::__construct($message, $code);
//        self::log($this->__toString());
    }
    //PHP的错误级别
    public static $type =  array(
        '1' => 'E_ERROR ',
        '2' => 'E_WARNING  ',
        '4' => 'E_PARSE  ',
        '8' => 'E_NOTICE  ',
        '16' => 'E_CORE_ERROR  ',
        '32' => 'E_CORE_WARNING  ',
        '64' => 'E_COMPILE_ERROR  ',
        '128' => 'E_COMPILE_WARNING  ',
        '256' => 'E_USER_ERROR  ',
        '512' => 'E_USER_WARNING  ',
        '1024' => 'E_USER_NOTICE  ',
        '2048' => 'E_STRICT  ',
        '4096' => 'E_RECOVERABLE_ERROR  ',
        '8191' => 'E_ALL  ',
    );

    /**
     * 通过数字 置换 对应的英文
     * @param $key
     * @return mixed
     * User: LiZheng  271648298@qq.com
     * Date: 2019/3/21
     */
    public static function get_type($key)
    {
        if(isset(self::$type[$key]))
        {
            return self::$type[$key];
        }else
        {
            return $key;
        }
    }
}

 

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
如何处理 PHP 的错误与异常(笔记)

这话题已经没有什么新意了,这里只是做做笔记,作为思路的一种整理,也以便后续忘了可以回来这里查找。 错误 以下是 PHP 最常见的几种错误: 运行上面代码,页面输出以下信息: 在生产环境下...

aisuhua
2019/09/29
0
0
php异常处理小总结

2019年8月23日10:56:31 php很多开发不习惯使用异常处理,因为web开发,重在于快速开发,易用性,高性能,不强调程序健壮性 php的异常使用其实不是太完善,易用性也差点,当然这个对比其他语言...

zh7314
2019/08/23
0
0
PHP错误与异常处理

请一定要注意,没有特殊说明:本例 PHP Version < 7   说起PHP异常处理,大家首先会想到try-catch,那好,我们先看一段程序吧:有一个test.php文件,有一段简单的PHP程序,内容如下,然后命...

osc_afhuw317
2019/07/25
2
0
PHP错误与异常处理

https://www.cnblogs.com/zyf-zhaoyafei/p/6928149.html   请一定要注意,没有特殊说明:本例 PHP Version < 7   说起PHP异常处理,大家首先会想到try-catch,那好,我们先看一段程序吧:...

osc_44jaxl0s
2019/02/14
2
0
PHP错误与异常处理

https://www.cnblogs.com/zyf-zhaoyafei/p/6928149.html 说起PHP异常处理,大家首先会想到try-catch,那好,我们先看一段程序吧:有一个test.php文件,有一段简单的PHP程序,内容如下,然后命...

osc_3f97qblr
2019/05/22
2
0

没有更多内容

加载失败,请刷新页面

加载更多

如果你失明了,你怎么编程? - How can you program if you're blind?

问题: Sight is one of the senses most programmers take for granted. 视觉是大多数程序员认为理所当然的感官之一。 Most programmers would spend hours looking at a computer monitor......

技术盛宴
30分钟前
12
0
如何删除使用Python的easy_install安装的软件包? - How do I remove packages installed with Python's easy_install?

问题: Python's easy_install makes installing new packages extremely convenient. Python的easy_install使安装新包非常方便。 However, as far as I can tell, it doesn't implement th......

fyin1314
今天
11
0
如何将逗号分隔的字符串转换为数组? - How to convert a comma separated string to an array?

问题: I have a comma separated string that I want to convert into an array, so I can loop through it. 我有一个逗号分隔的字符串,我想将其转换成数组,因此可以循环遍历它。 Is the...

富含淀粉
今天
13
0
深源恒际:担心个人身份被冒用?不存在!

本文作者:c****t 近日,苟晶被冒名顶替身份参加高考的事件在社会各界掀起广泛热议。事件调查结果公布后,舆论风向逆转,吃瓜群众认为当事人夸大其词消费了公众情绪,一边对当事人所遭遇的不...

百度开发者中心
昨天
5
0
CKEditor 5 + SpringBoot实战(三):SpringData JPA数据持久化

在本系列的文章中,我将介绍如何在Spring Boot Application中使用CKEditor编辑器。介绍的内容包括基本环境的搭建,文件上传,SpringData JPA数据持久化,CKEditor5的安装,CKEditor图片上传,...

树下魅狐
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部