Числа в PHP: типы данных, преобразование и безопасное использование
Основные способы работы с числами
Наиболее эффективный и безопасный подход для работы с числами в PHP - использование комбинации filter_var с соответствующими флагами для валидации и последующего приведения типа. Этот метод позволяет одновременно проверить, является ли значение целым числом или числом с плавающей точкой, и получить корректный результат или false в случае ошибки. Например:
$input = '42';
$int = filter_var($input, FILTER_VALIDATE_INT);
if ($int === false) {
echo 'Некорректное целое число';
} else {
echo $int; // 42
}
$float = filter_var('3.14', FILTER_VALIDATE_FLOAT);
var_dump($float); // float(3.14)Такой подход исключает проблемы с неявным приведением типов и позволяет обработать ошибочные данные до их использования в вычислениях. Для дальнейших операций над числами (округление, форматирование, математические расчёты) применяются встроенные функции PHP.
Как преобразовать строку в целое число без проверки?
Функция intval и приведение типа (int) преобразуют значение в целое число, отбрасывая всё, что не является цифрой в начале строки. Однако это может привести к неожиданным результатам, если входные данные содержат нечисловые символы.
$str = '123abc';
echo intval($str); // 123
echo (int)$str; // 123
$str2 = 'abc123';
echo intval($str2); // 0Типичная ошибка: использование intval или (int) на строке, начинающейся с букв, даёт 0, что может быть воспринято как корректное значение. Решение - предварительная проверка через filter_var или ctype_digit.
Как преобразовать строку в число с плавающей точкой?
Аналогично используются floatval и приведение (float):
$str = '3.14abc';
echo floatval($str); // 3.14
echo (float)$str; // 3.14
$str2 = 'abc3.14';
echo floatval($str2); // 0Проблема: те же риски, что и с целыми. Кроме того, из-за особенностей двоичного представления чисел с плавающей точкой результат может содержать ошибки округления (например, 0.1 + 0.2 ≠ 0.3). Для финансовых вычислений рекомендуется использовать расширение BCMath.
Как проверить, является ли значение числом?
PHP предоставляет несколько функций: is_numeric, is_int, is_float, ctype_digit.
$values = ['42', '3.14', '1e3', 'abc', 42, 3.14];
foreach ($values as $v) {
echo is_numeric($v) ? 'число' : 'не число';
echo ' | ';
echo is_int($v) ? 'int' : '';
echo is_float($v) ? 'float' : '';
echo "\n";
}Ошибка: is_numeric возвращает true для чисел в научной нотации (например, '1e3'), что может быть нежелательно при проверке пользовательского ввода. ctype_digit проверяет только целые положительные числа без знака. Для строгой валидации лучше использовать filter_var.
Как округлить число до заданного количества знаков?
Функция round округляет по правилам математического округления. ceil округляет вверх, floor - вниз. Для форматирования с фиксированным количеством десятичных знаков используется number_format.
$num = 3.14159;
echo round($num, 2); // 3.14
echo ceil($num); // 4
echo floor($num); // 3
echo number_format($num, 2, '.', ''); // 3.14Проблема: round может давать неожиданные результаты для чисел с плавающей точкой (например, round(2.5, 0, PHP_ROUND_HALF_UP) vs round(2.5, 0, PHP_ROUND_HALF_EVEN)). Рекомендуется явно указывать режим округления при необходимости.
Как избежать ошибок точности при работе с float?
Для точных вычислений (финансы, научные расчёты) используется расширение BCMath (binary calculator) или GMP для целых чисел произвольной длины.
$a = '0.1';
$b = '0.2';
$sum = bcadd($a, $b, 2); // 0.30
echo $sum; // 0.30
// Сравнение float
if (bccomp($a, $b, 10) == 0) {
echo 'равны';
} else {
echo 'не равны';
}Ошибка: стандартное сравнение чисел с плавающей точкой через == может дать false, даже если теоретически они равны (0.1 + 0.2 == 0.3 - false). Решение - использование bccomp или сравнение с эпсилоном: abs($a - $b) < 1e-10.
Расширенные примеры работы с числами в PHP.
Пример 1: Точные вычисления с BCMath
$price = '19.99';
$quantity = '3';
$taxRate = '0.07';
$subtotal = bcmul($price, $quantity, 2); // 59.97
$tax = bcmul($subtotal, $taxRate, 2); // 4.20
$total = bcadd($subtotal, $tax, 2); // 64.17
echo "Итоговая сумма: $total";Итоговая сумма: 64.17
Пример 2: Форматирование чисел с учётом локали
setlocale(LC_NUMERIC, 'de_DE.UTF-8');
$num = 1234567.89;
echo number_format($num, 2, ',', '.'); // 1.234.567,89
// Использование NumberFormatter
$fmt = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(1234567.89, 'EUR'); // 1.234.567,89 €1.234.567,89 €
Пример 3: Генерация криптостойких случайных чисел
// Случайное целое от 1 до 100
$secureInt = random_int(1, 100);
echo $secureInt;
// Случайное число с плавающей точкой от 0 до 1 (не криптостойко, но для примера)
$randomFloat = mt_rand() / mt_getrandmax();
// Для криптостойкого float: unpack('f', random_bytes(4))[1] (требуется осторожность)(например) 47
Пример 4: Обработка чисел из CSV-файла
$csv = "123;45.67;abc\n89;0.01;xyz";
$lines = explode("\n", $csv);
$numbers = [];
foreach ($lines as $line) {
$parts = explode(';', $line);
foreach ($parts as $part) {
$num = filter_var($part, FILTER_VALIDATE_FLOAT);
if ($num !== false) {
$numbers[] = $num;
}
}
}
print_r($numbers);Array
(
[0] => 123
[1] => 45.67
[2] => 89
[3] => 0.01
)Пример 5: Работа с большими целыми числами через GMP
$factorial = gmp_fact(100);
echo gmp_strval($factorial);
// 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000(гигантское число)
Пример 6: Преобразование систем счисления
$hex = 'ff';
$dec = hexdec($hex); // 255
$bin = decbin($dec); // 11111111
$oct = decoct($dec); // 377
echo "HEX: $hex -> DEC: $dec -> BIN: $bin -> OCT: $oct";HEX: ff -> DEC: 255 -> BIN: 11111111 -> OCT: 377
Пример 7: Арифметика на 64-битных числах с переполнением
// PHP автоматически преобразует int в float при переполнении
$big = PHP_INT_MAX;
$bigger = $big + 1;
var_dump($bigger); // float(9.2233720368548E+18) - потеря точности
// Для сохранения точности используем BCMath
$bcResult = bcadd((string)$big, '1', 0);
echo $bcResult; // 9223372036854775808 (точное значение)float(9.2233720368548E+18) 9223372036854775808