最近在项目中前端的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