PHP 7 不一致地抛出除以零的错误

Kat*_*tie 5 php error-handling php-7

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

在 PHP 文档中DivisionByZeroError,它指出:

当尝试将数字除以零时抛出 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";
}
Run Code Online (Sandbox Code Playgroud)

相反,只有第一个被捕获:

抓住了 DivisionByZeroError!

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

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

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

bis*_*hop 2


NOTE: The Engine Warnings RFC has changed the behavior. PHP 8+ will now always throw an exception when dividing by zero. PHP 7- exhibits the behavior described below.


I don't think it's this way for backward compatibility. Rather, I feel it's implemented this way for consistency with other languages: the division operator conforms to the IEEE-754 definition of floating point division. In one, and only one, circumstance will it perform integer division, equivalent to intdiv:

The division operator ("/") returns a float value unless the two operands are integers (or strings that get converted to integers) and the numbers are evenly divisible, in which case an integer value will be returned. For integer division, see intdiv().

重要的是,遗憾的是, DivisionByZeroError 文档中没有提及,它仅在执行整数除法时才会引发。如果开发人员打算进行整数除法,intdiv或者%需要。否则,开发人员仍必须检查股息是否接近零条件并进行相应处理(与所有其他浮点运算的情况一样)。

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

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

但是,它不会捕获除零警告正是因为它是警告而不是例外。