BCMath: Новая функция bcdivmod
bcdivmod
может быть использован в случаях, когда необходимо получить частное и остаток от деления, и избавляет от необходимости вызывать функции bcdiv
и bcmod
по отдельности.В PHP 8.4 в расширении BCMath представлена новая функция bcdivmod
, делящая заданное число на заданный делитель и возвращающая как частное, так и остаток. Результат по сути идентичен вызову функций bcdiv
и bcmod
.
Возвращаемое значение — массив, в котором первое значение — частное от деления, а второе — остаток.
bcdivmod('42', '10');
// ["4", "2"]
Синопсис функции bcdivmod
/**
* @param string $num1 Делимое, как строка.
* @param string $num2 Делитель, как строка.
* @param int|null $scale Количество цифр после десятичного знака в остатке.
* Если это значение опущено или равно null, то по умолчанию будет использоваться
* значение, установленный глобально с помощью функции bcscale(), или резервное
* значение bcmath.scale INI (по умолчанию равно 0), если оно не было установлено.
*
* @return array
*/
function bcdivmod(string $num1, string $num2, ?int $scale = null): array {}
bcdivmod
объявляется в глобальном пространстве имён.- Если значение количества знаков после запятой равно
null
, то наследуется значение, заданное функциейbcscale
, с резервным значением INIbcmath.scale
. - Возвращаемое значение всегда представляет собой массив.
- Передача 0 для параметра
$num2
вызывает исключениеDivisionByZeroError
. - Передача нечисловой строки для параметров
$num1
или$num2
вызывает исключениеValueError
, говорящее, что значение сформировано неверно.
bcdivmod
возвращает массив, содержащий частное (целое значения) в виде строки, и остаток — в виде строки, содержащей $scale
количество знаков после запятой.
Примеры использования bcdivmod
bcdivmod("10", "10");
// ["1", "0"]
bcdivmod("10", "100");
// ["0", "10"]
// Использование значения по умолчанию bcmath.scale INI = 0
bcdivmod("8957", "5.43242");
// ["1648", "4"]
// Установка значения scale
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. Если не существует глобальной функции с таким же именем, это изменение не должно вызвать проблем с обратной совместимостью.
Следующий полифилл PHP использует функции bcdiv
и bcmod
и совместим с 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),
];
}