请问php异常处理为何无效 `Warning: Division by zero`?

<?php
$a = 1;
$b =0;
try{
    echo $a/$b;
}catch(Exception $e){
    echo '发送错误:被除数不能为0';
}

输出结果如下

Warning: Division by zero in D:\phpstudy_pro\WWW\demo.php on line 5
INF
阅读 3.5k
2 个回答

简单的说,因为这个在这里目前是一个 Warning 而不是一个 Exception。

而 Warning 属于 Error 的一部分,虽然 PHP 7 错误处理 的介绍中提到了。

PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。

没错,只是大多数的被作为 Error 异常抛出了,但是除零这种情况并不包含在内(其实还有很多情况都不会转为异常抛出)。

其他答主已经介绍过, PHP 7 开始 Throwable 可以捕获来自 Error 的异常并进行处理。

image.png

看到上图,你应该注意到了 DivisionByZeroError 这一个属于错误下的类,但是如果你在 PHP 7 版本中运行这段代码。

<?php

try{
    $result = 1 / 0;
}catch(Throwable $t){
    var_dump($t);
}

你就会发现,也并没有捕获到这个异常,满头问号吧 ❓❓❓。

好吧,在 PHP 7 中,只是将 %(取模)在模 0 的时候会触发 DivisionByZeroError 这个异常类。不信你把上面代码改一下。

<?php

try{
    $result = 1 % 0;
}catch(Throwable $t){
    var_dump($t);
}

你会发现,现在就可以捕获到这个 DivisionByZeroError 异常了。

那,就没有办法来处理这个 Error 了吗?

当然可以,要在 PHP 7 及以前的版本中处理这个可以使用 set_error_handler 这个函数,来注册一个错误处理函数,这样当发生错误时,就会把错信息传递到这个函数来。

你可以在这个函数中什么也不做(那么将当作无事发生,代码将继续运行)

<?php

set_error_handler(function () {
    var_dump('发生错误啦!');
});

try {
    $result = 1 / 0;
    var_dump('我会显示。');
} catch (Throwable $t) {
    var_dump('我不会显示。');
}

var_dump('可以运行到这里喔');

上面的代码则会打印:

发生错误啦!
我会显示。
可以运行到这里喔!

你可以在这个处理函数中抛出一个异常,这样你就能在 catch 里面捕获到了。

<?php

set_error_handler(function ($code, $msg) {
    throw new DivisionByZeroError($msg, $code);
});

try {
    $result = 1 / 0;
    var_dump('我不会显示!');
} catch (Throwable $t) {
    var_dump('捕获到啦!');
}
var_dump('我会显示!');

上面的代码将会一次打印

捕获到啦!
我会显示!

但,自 PHP 8 起,PHP RFC: Reclassifying engine warnings 这个 RFC 通过后,除零也改为了抛出 DivisionByZeroError 异常,所以,自 PHP 8 开始,你就可以直接捕获到这个异常了。

很久很久以前,PHP只有Error没有Exception,PHP5才引入Exception的异常概念,可以手动throw让try/catch捕获

所以在PHP5时代,你有两个选择处理这个Warning错误

  1. 开发环境通过php.ini配置直接显示,而不需要try/catch手动处理,这样简单粗暴方便调试,而在开发阶段没发现的,带到了生产环境,则配置记录错误,有问题了通过错误日志去查,然后修复这个错误
  2. 主动判断并手动抛出异常,让try/catch捕获,如下
<?php
$a = 1;
$b = 0;
try{
    if($b==0){
        throw new Exception("手动抛出异常,0不能作为除数");
    }
    $result = $a / $b;
}catch(Exception $e){
    var_dump($e);
}

输出结果

object(Exception)#1 (7) {
  ["message":protected]=>
  string(40) "手动抛出异常,0不能作为除数"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(28) "/Users/charles/Desktop/b.php"
  ["line":protected]=>
  int(6)
  ["trace":"Exception":private]=>
  array(0) {
  }
  ["previous":"Exception":private]=>
  NULL
}

而在PHP7时代,引入了全新的Throwable来处理Error和Exception,因为Error和Exception都继承自Throwable,所以Throwable终于可以同时处理错误和异常,示例代码如下

<?php

try{
    $result = 1 / 0;
}catch(Throwable $t){
    var_dump($t);
}

输出结果

object(DivisionByZeroError)#1 (7) {
  ["message":protected]=>
  string(16) "Division by zero"
  ["string":"Error":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(28) "/Users/charles/Desktop/a.php"
  ["line":protected]=>
  int(4)
  ["trace":"Error":private]=>
  array(0) {
  }
  ["previous":"Error":private]=>
  NULL
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏