【问题标题】:PHP 7 inconsistently throwing errors for division by zeroPHP 7 不一致地抛出除以零的错误
【发布时间】:2020-12-03 16:46:17
【问题描述】:

我目前正在尝试了解 PHP 7 中新错误处理的行为。

DivisionByZeroError 的 PHP 文档中,它指出:

DivisionByZeroError 当试图分割一个 数字为零。

很公平,但在使用 / 运算符时不会抛出 DivisionByZeroError。

在这个例子中,我希望两个错误都被捕获:

declare(strict_types=1);
function usesIntDiv(int $a, int $b) {
    return intdiv($a,$b);
}

function divide(int $a, int $b) {
    return $a / $b;
}

try {
    echo usesIntDiv(2,0);
} catch (DivisionByZeroError $e) {
    echo "Caught DivisionByZeroError!\n";
}

echo "\n";

try {
    echo divide(2,0);
} catch (DivisionByZeroError $e) {
    echo "Caught DivisionByZeroError!\n";
}

而是只捕获第一个:

发现除零错误!

PHP 警告:第 9 行的 TypeError.php 中除以零...

为什么?还有其他类似的情况吗?我的理解是,如果你捕捉到Throwable,你将捕捉到任何可以引发的东西,这将使 PHP 错误处理更易于管理。但是在这种情况下,如果我使用/ 运算符,它是无法捕获的PHP 警告。

这是特定于这个错误(可能是因为它是由操作员触发的),还是我误解了错误处理的变化?

【问题讨论】:

  • php 的一点澄清“以前,当 0 用作除数 (/) 或模数 (%) 运算符的除数时,将发出 E_WARNING 并返回 false . 现在,除法运算符返回一个浮点数,如 IEEE 754 所指定的 +INF、-INF 或 NAN。模运算符 E_WARNING 已被删除,并将引发 DivisionByZeroError 异常。"
  • 文字语法给出警告,intdiv() 抛出异常。这绝对是不一致的,但在这一点上很难改变。更改为引发异常会破坏许多使用 === INF 进行比较的现有代码(并关闭/忽略警告)。向后兼容性可能是造成这种不一致的原因。
  • 感谢深思熟虑的 cmets 指出这种情况可能是为了向后兼容,所以如果它只是一次性的,那么至少 DivisionByZeroError 的 PHP 文档应该警告这种不一致。但它没有回答另一个问题,我认为如果你抓住 Throwable,你就会抓住一切,似乎并非如此。 PHP 错误处理的泥潭在 PHP 7 中进一步加深。
  • @Katie PHP 8 现在总是在除以零时抛出异常。
  • @bishop - 好消息 :)

标签: php error-handling php-7


【解决方案1】:

注意:Engine Warnings RFC 改变了行为。 PHP 8+ 现在将总是在除以零时抛出异常。 PHP 7- 表现出如下所述的行为。


我不认为这种方式是为了向后兼容。相反,我觉得它以这种方式实现是为了与其他语言保持一致:除法运算符符合浮点除法的IEEE-754 definition。一种,也只有一种,circumstance会进行整数除法,相当于intdiv

除法运算符(“/”)返回一个浮点值,除非两个操作数是整数(或转换为整数的字符串)并且数字是可整除的,在这种情况下将返回一个整数值。整数除法见 intdiv()。

重要的是,很遗憾,DivisionByZeroError doc 中没有提到它仅在执行 integer 除法时才被提出。如果开发人员打算进行整数除法,则需要intdiv%。否则,开发人员仍必须检查股息是否接近零并进行相应处理(与所有其他浮点运算一样)。

从问题中不清楚Throwable 发生了什么问题,但Throwable 确实抓住了DivisionByZeroError

try {                                                                            
    intdiv(2, 0);                                                                
} catch (\Throwable $t) {                                                        
    echo 'caught' . PHP_EOL;                                                     
}                                                                                

但是,它不会捕获除以零警告,正是因为它是警告而不是异常。

【讨论】:

    【解决方案2】:

    算术运算符/的使用在php 7中不会抛出异常,而在php 8中会抛出异常。代码解释见下文。

    <?php
    
    try {
        echo intdiv(2, 0);
    } catch (DivisionByZeroError $e) {
        echo "caught division by zero for intdiv()\n";
    }
    
    try {
        echo (2 / 0);
    } catch (DivisionByZeroError $e) {
        echo "caught division by zero for /\n";
    }
    
    # php 7
    $ php test.php
    caught division by zero for intdiv()
    PHP Warning:  Division by zero in test.php on line 10
    PHP Stack trace:
    PHP   1. {main}() test.php:0
    
    Warning: Division by zero in test.php on line 10
    
    Call Stack:
        0.0740     417272   1. {main}() test.php:0
    
    # php 8
    $ php test.php
    
    caught division by zero for intdiv()
    caught division by zero for /
    

    【讨论】:

      猜你喜欢
      • 2011-11-08
      • 1970-01-01
      • 1970-01-01
      • 2016-02-23
      • 2020-01-05
      • 1970-01-01
      • 2013-06-19
      • 2021-02-02
      • 1970-01-01
      相关资源
      最近更新 更多