您的位置:晶晶的博客>PHP>PHP的异常处理机制

PHP的异常处理机制

PHP中异常和错误相生相辅,甚至到PHP7后都有一点不分彼此的意味了,猜测PHP往后发展会越来越弱化错误而强化异常,这也是一门语言由欠缺走向完美的进化过程。PHP中有关错误的内容见此:https://blog.jjonline.cn/phptech/228.html

PHP的异常概要

PHP7改变了大多数错误的报告方式,不同于PHP7之前版本的错误报告机制,现在大多数错误被作为Error异常抛出。PHP7实现了一个全局的所有可以通过throw语句抛出的异常的throwable基础接口(interface),原有的Exception和新增的部分Error都实现(implements)了这个接口, 以接口的方式定义了异常的继承结构,也明确了Exception和各种Error都可以被当做一种可抛出的异常来处理。

要知道的是目前PHP7中并不是所有的错误均实现了throwable接口或继承至PHP7新增的Error类,原先PHP5中的一些错误特别是一些E_PARSEE_ERROR级别的致命错误在PHP7中变为了可捕获的throwable(Exception对象或子对象和Error对象或子对象),如果不进行捕获则为一个错误,如果捕获就变为一个可在程序内处理的异常(throwable)。

基于上述分析可以这样理解:PHP7中的异常所表示的范围相对于PHP5更为宽泛了,既包含了PHP5中的Exception又新增了PHP7才加入的Error,而Exception和Error又都是实现了throwable接口,所以呢PHP7之后谈到异常首先应该想到的是throwable而不是Exception。层次结构如下:

throwable层次结构

PHP中的异常处理

与PHP的错误处理类似,PHP也提供有callable set_exception_handler(callable $exception_handler)函数,用于注册默认的异常处理回调函数,用于统一处理没有用 try/catch 语句块捕获的异常。其中这个回调函数exception_handler需要接受一个参数,该参数即为异常所发生位置抛出的异常对象,PHP7之前这个参数的类型为Exception,PHP7开始这个参数的类型被提升为Throwable,所以在代码中注册异常处理回调函数时显式的指定回调函数的参数类型为Exception的话可能会导致PHP7中参数类型错误即TypeError,而显式的指定该回调函数的参数类型为Throwable会导致低版本PHP找不到类的错误,也就是说下方两种注册异常回调函数的写法是会出现兼容问题的,正确的写法是注册的回调函数的参数不显式指定类型。在异常回调函数被调用后脚本会中止执行。 

# 不向上兼容PHP7
set_exception_handler(function (Exception $e) {
    echo 'Throw Exception: '.$e->getMessage();
});

# 不向下兼容PHP5
set_exception_handler(function (Throwable $e) {
    echo 'Throw Exception: '.$e->getMessage();
});

# 同时兼容
set_exception_handler(function ($e) {
    echo 'Throw Exception: '.$e->getMessage();
});

下方这段代码拿来抛砖引玉,分别在PHP5.6.30和PHP7.0.19中运行并分析输出结果的差异和原因:

<?php
/**
 * 
 * @authors Jea杨 (JJonline@JJonline.Cn)
 * @date    2017-06-06 13:48:51
 * @version $Id$
 */

### file1.php 公共起始部分代码

# step1、设定错误报告级别
error_reporting(E_ALL | E_STRICT);

# step2、注册自动加载机制
# 代码省略
# 核心要素是使用spl_autoload_register函数注册PHP类自动加载的回调函数
# 魔法函数__autoload() 以及其默认实现 spl_autoload均不再建议使用

# step3、注册Error、Exception以及脚本运行完毕退出时执行的回调函数
set_error_handler(function ($errno , $errstr , $errfile, $errline) {
    // E_WARNGING、E_NOTICE级别的错误有关处理,例如:记录log、分开发环境或生产环境的界面友好显示等
    ## 此处直接将错误信息托管至ErrorException
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

set_exception_handler(function ($e) {
    // 注册未使用try catch语句捕获异常的异常统一处理逻辑
    // 其中$e参数是异常对象 \Exception PHP7引入了一个Error和Exception的接口\Throwable
    echo 'Throw Exception: '.$e->getMessage();
});

register_shutdown_function(function () {
    $error = error_get_last();
    /**
     * 如果获取到的最后的错误信息不是null(即没有出错)
     * 且错误信息的类型是属于E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE这几个级别
     * 则是set_error_handler回调函数所无法处理的致命错误类型
     */
    if(!is_null($error) && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]))
    {
        echo 'Fatal Error';
    }
});

# step4、session、cookie相关设定
# 代码省略
# 
# 
# ++++++++++++++++++++++++++++++++++++++++++++++++
# 上述分为step1至step4不一定非得如此,只是一个建议
# 也不一定非编写成面向过程的代码风格
# 也可以写成一个Class类,其他代码文件利用自动
# 加载机制优先加载即可
# ++++++++++++++++++++++++++++++++++++++++++++++++

test();

echo '执行到这儿啦~~';

PHP7.0.19下运行的结果为:

Throw Exception: Call to undefined function test()

截图如下:

php7.0异常截图

PHP5.6.30下运行的结果为:

Fatal error: Call to undefined function test() in /wwwRoot/OpenSource/php_error/file1.php on line 56
Fatal Error
PHP5致命错误报错截图

上述代码的问题是函数test不存在未定义;在PHP5和PHP7不同版本中的报错信息其原理是有差异的,PHP5中实质是在register_shutdown_function注册的回调函数中处理的这个fatal error,而且PHP默认的错误处理提示消息也显示了出来,因为是fatal error也就是致命错误,并不能触发由set_error_handler注册的错误处理回调函数,而且致命错误会导致脚本终止,所以输出结果中没有输出执行到这儿啦~~这段文字。而在PHP7中函数不存在这个致命错误已经变成了一个Error异常,因为没有用try/catch语句捕获处理,最终由set_exception_handler定义的回调函数所处理并终止了代码运行,所以输出结果中也没有输出执行到这儿啦~~这段文字。

转载请注明本文标题和链接:《PHP的异常处理机制

相关推荐

哟嚯,本文评论功能关闭啦~