php的Error与Exception捕获问题

在PHP项目中,遇到一个使用try...catch...未捕获到的错误导致脚本中断的问题。分析发现,由于错误级别被判定为Error而非Exception,因此没有被捕获。在PHP7之后,Error和Exception都继承了Throwable接口,可以被捕获。文章探讨了Error与Exception的区别,以及如何在PHP中正确处理Error和Exception。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在项目中前端的php同事发现后台有个php导出的脚本,没有完成就挂掉了,使用try..catch..方式并没有捕获到异常。代码是这样写的

try {
    $res = $this->doExprot();
} catch (\Exception $e) {
    $msg = '导出程序异常,被杀死 ******* 错误信息:' . $e->getMessage() . ' ************';
    $res = $e->getTraceAsString();
    $this->threadPool->killThread($this->threadPool->getRedisThreadsKeyPre(), $export_log_id, $msg);
} finally{
    $this->log($supplier_id, $export_log_id, $res);
}

日志捕获到的错误为:
这里写图片描述

项目使用的php-7.1.2,框架是larval5.3。根据有日志显示,但是后续捕获日志以及相关逻辑都没有执行,推断程序已经意外中断。到服务器上ps下pid果然没有了。那么为什么没有catch到呢。

进入larval框架下查看Symfony\Component\Debug\Exception\FatalThrowableError源码

class FatalThrowableError extends FatalErrorException
{
    public function __construct(\Throwable $e)
    {
        if ($e instanceof \ParseError) {
            $message = 'Parse error: '.$e->getMessage();
            $severity = E_PARSE;
        } elseif ($e instanceof \TypeError) {
            $message = 'Type error: '.$e->getMessage();
            $severity = E_RECOVERABLE_ERROR;
        } else {
            $message = $e->getMessage();
            $severity = E_ERROR;
        }

        \ErrorException::__construct(
            $message,
            $e->getCode(),
            $severity,
            $e->getFile(),
            $e->getLine()
        );

        $this->setTrace($e->getTrace());
    }
}

通过对message的判断

local.ERROR: Symfony\Component\Debug\Exception\FatalThrowableError: Cannot use object of type stdClass as array in。。。

知道程序定义错误级别走的为

$message = $e->getMessage();
$severity = E_ERROR;

在判定程序错误级别以及错误信息后,执行ErrorException。but。。这位同事just catch Exception。这就是问题点,解决方式很好处理,只需要增加Error的异常捕获就可以。

try {
    $res = $this->doExprot();
} catch (\Exception $exception) {

    $msg = '导出程序异常,被杀死 ******* 错误信息:' . $exception->getMessage() . ' ************';
    $res = $exception->getTraceAsString();
    $this->threadPool->killThread($this->threadPool->getRedisThreadsKeyPre(), $export_log_id, $msg);
} catch(\Error $error) {
    $msg = '导出程序异常,被杀死 ******* 错误信息:' . $error->getMessage() . ' ************';
    $res = $error->getTraceAsString();
    $this->threadPool->killThread($this->threadPool->getRedisThreadsKeyPre(), $export_log_id, $msg);
}finally{
    $this->log($supplier_id, $export_log_id, $res);
}

Error级别定义

Fatal Error:致命错误(脚本终止运行)
        E_ERROR         // 致命的运行错误,错误无法恢复,暂停执行脚本
        E_CORE_ERROR    // PHP启动时初始化过程中的致命错误
        E_COMPILE_ERROR // 编译时致命性错,就像由Zend脚本引擎生成了一个E_ERROR
        E_USER_ERROR    // 自定义错误消息。像用PHP函数trigger_error(错误类型设置为:E_USER_ERROR)

    Parse Error:编译时解析错误,语法错误(脚本终止运行)
        E_PARSE  //编译时的语法解析错误

    Warning Error:警告错误(仅给出提示信息,脚本不终止运行)
        E_WARNING         // 运行时警告 (非致命错误)。
        E_CORE_WARNING    // PHP初始化启动过程中发生的警告 (非致命错误) 。
        E_COMPILE_WARNING // 编译警告
        E_USER_WARNING    // 用户产生的警告信息

    Notice Error:通知错误(仅给出通知信息,脚本不终止运行)
        E_NOTICE      // 运行时通知。表示脚本遇到可能会表现为错误的情况.
        E_USER_NOTICE // 用户产生的通知信息。

那么再php中Exception和Error有什么区别呢。
在我看来,Error是检测到的这个问题极有可能使程序无法继续运行,而Exception则是虽然有问题但是程序继续运行不受影响。在php7以前的版本中Error类型是不能被捕获的,仅仅可以捕获Exception类型。php7以后Error与Exception都继承了Throwable接口,使得Error被捕获成为可能。
php官方是这么介绍Error的

Error is the base class for all internal PHP errors.Since PHP 7 classname "Error" is predefined and used internally.

Error是所有内部php错误的基本类,并且自从php7以后Error这个类名,您呀就别用了。。。
其他处理错误的方式大家可以看看怎么运用register_shutdown_function,set_error_handler,set_exception_handler这三个神奇的函数,在php7以下的版本也可以捕获Error

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值