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.scale
INI 值。 - 返回值永远是数组。
$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),
];
}