PHP 8.4: BCMath: 新增 bcdivmod 函数
PHP 8.4 中的 BCMath 扩展引入了一个名为 bcdivmod 的新函数,该函数将给定的数字除以给定的除数,并返回商和余数。结果与调用 bcdiv 和 bcmod 函数基本相同。
bcdivmod 可用于需要商和余数的用例,它避免了必须分别调用 bcdiv 和 bcmod 函数。
返回值是一个数组,第一个值是商,第二个值是余数。
bcdivmod('42', '10');
// ["4", "2"]bcdivmod 函数摘要
/**
* @param string $num1 Dividend, as a string.
* @param string $num2 Divisor, as a string.
* @param int|null $scale Number of digits after the decimal place in the
* remainder. If omitted or null, it will default to the scale set globally
* with the bcscale() function, or fallback bcmath.scale INI value
* (default to 0) if this has not been set.
*
* @return array
*/
function bcdivmod(string $num1, string $num2, ?int $scale = null): array {}bcdivmod在全局命名空间中声明- 如果
scale值为null,则它将继承使用bcscale函数设置的 scale 值,并回退到bcmath.scaleINI 值。 - 返回值永远是数组。
$num2参数传入0将会抛出DivisionByZeroError异常。- 为
$num1或$num2参数传递非数字字符串会引发ValueError异常,指出该值格式不正确。
bcdivmod 返回一个数组,其中商(整数值)为字符串,余数为包含 $scale 个十进制值的字符串。
用例
bcdivmod("10", "10");
// ["1", "0"]bcdivmod("10", "100");
// ["0", "10"]// Using default bcmath.scale INI value = 0
bcdivmod("8957", "5.43242");
// ["1648", "4"]// Setting scale value
bcdivmod("8957", "5.43242", 10);
// ["1648", "4.3718400000"]bcdivmod("8957.5454312", "5.43242", 10);
// ["1648", "4.9172712000"]bcdivmod("0", 42);
// ["0", "0"]bcdivmod 错误条件
bcdivmod 函数遵循与 BCMath 扩展中的其他函数类似的语义。传递非数值会引发 ValueError 异常,并且由于 $num1 和 $num2 参数的类型声明是字符串,因此在声明 declare(strict_types=1) 生效时,它遵循标准的 PHP 类型强制和严格的类型规则。
将零作为除数时将抛出 DivisionByZeroError:
bcdivmod("42", "0");DivisionByZeroError: Division by zero将非数值字符串和 INF 传递给 $num1 或 $num2 将抛出 ValueError:
bcdivmod("42", "foobar");ValueError: bcdivmod(): Argument #2 ($num2) is not well-formed.向后兼容性影响
bcdivmod 是 PHP 8.4 BCMath 扩展中添加的一个新函数。除非存在同名的现有全局函数,否则此更改不应导致任何向后兼容性问题。
以下是一个使用 bcdiv 和 bcmod 函数的 PHP polyfill,与 PHP 8.0 及更高版本兼容:
/**
* @param string $num1 Dividend, as a string.
* @param string $num2 Divisor, as a string.
* @param int|null $scale Number of digits after the decimal place in the
* remainder. If omitted or null, it will default to the scale set globally
* with the bcscale() function, or fallback to bcmath.scale INI value (default to 0) if this has not been set.
*
* @return array
*/
function bcdivmod(string $num1, string $num2, ?int $scale = null): array {
if (!is_numeric($num1)) {
throw new \ValueError('Argument #1 ($num1) is not well-formed');
}
if (!is_numeric($num2)) {
throw new \ValueError('Argument #2 ($num2) is not well-formed');
}
if ($num2 === '0') {
throw new \DivisionByZeroError('Division by zero');
}
return [
\bcdiv($num1, $num2, 0),
\bcmod($num1, $num2, $scale),
];
}