Типы данных в PHP: от целых чисел до объектов
Типы данных и их размеры в PHP
PHP поддерживает несколько типов данных, каждый из которых занимает определённый объём памяти. Размеры зависят от архитектуры системы (32- или 64-битная) и версии интерпретатора. Ниже приведены основные типы и их приблизительные размеры:
- int - 4 или 8 байт (целое число).
- float - 8 байт (число с плавающей запятой).
- string - зависит от длины (каждый символ 1 байт для ASCII, до 4 байт для UTF-8) плюс служебные данные.
- bool - 1 байт.
- array - зависит от количества элементов и их типов (хеш-таблица).
- object - зависит от класса и свойств.
- null - 0 байт (специальное значение).
- resource - указатель на внешний ресурс (8 байт).
- callable - как функция (занимает память как строка или массив).
Для наглядного определения типа и размера используется функция var_dump(). Пример:
$number = 42;
var_dump($number);
$pi = 3.1415;
var_dump($pi);
$text = "Hello";
var_dump($text);
$flag = true;
var_dump($flag);
Type php type size (типы данных и их размеры php)
Результат вывода (на 64-битной системе):
int(42) float(3.1415) string(5) "Hello" bool(true)
Json types php (php: типы данных json)
Также можно измерить текущее потребление памяти с помощью memory_get_usage(). Однако размер переменной не равен разнице до и после присваивания из-за внутреннего менеджмента памяти.
Как узнать точный размер переменной в PHP?
Прямого способа нет, но можно оценить, используя сериализацию. Функция strlen(serialize($var)) показывает длину сериализованной строки, что косвенно указывает на размер данных.
$data = ['a' => 1, 'b' => 2];
echo strlen(serialize($data));
// Вывод: 30 (примерно)
Проблема: Сериализация добавляет служебные символы, поэтому результат не равен реальному размеру в памяти. Для точного анализа используйте профилировщики (Xdebug, Blackfire).
Как определить тип переменной без var_dump?
Функция gettype() возвращает название типа строкой. А функции is_int(), is_string() и другие проверяют принадлежность к конкретному типу.
$value = 3.14;
echo gettype($value); // double
var_dump(is_float($value)); // bool(true)
var_dump(is_int($value)); // bool(false)
Ошибка: gettype() для чисел с плавающей запятой возвращает double (а не float), хотя в PHP это одно и то же. Не стоит путать с float в документации.
Как преобразовать один тип в другой?
Используется явное приведение типа: (int), (string), (bool) и т.д. Также функции intval(), floatval(), strval().
$number = "123";
$int = (int) $number;
echo $int; // 123
echo gettype($int); // integer
Проблема: Приведение строки, не содержащей числа, даёт 0. Например, (int) "abc" вернёт 0. Это может привести к неожиданным ошибкам.
Как избежать ошибок из-за автоматического преобразования типов?
В PHP 7+ можно включить строгую типизацию объявлением declare(strict_types=1); в начале файла. Тогда передача аргументов неверного типа вызовет TypeError.
<?php
declare(strict_types=1);
function sum(int $a, int $b): int {
return $a + $b;
}
echo sum(5, 10); // 15
echo sum('5', 10); // TypeError: Argument 1 must be int
?>
Ошибка: Без strict_types PHP автоматически преобразует строку '5' в число. Это может скрывать логические ошибки.
Какие типичные проблемы возникают при работе с типами данных?
- Потеря точности float: Сравнение чисел с плавающей запятой через
==может дать ложный результат из-за погрешностей. Используйте эпсилон-сравнение. - Переполнение int: В 32-битных системах целое число больше 2^31-1 становится float. В 64-битных - до 2^63-1.
- Сравнение типов: Использование
==вместо===приводит к неявному преобразованию (например0 == 'abc'даёт true). - Ресурсы: Тип resource - это указатель, который может стать недействительным после закрытия (например, файл).
Для избегания проблем рекомендуется всегда использовать строгое сравнение === и явно указывать типы аргументов.
Расширенные примеры работы с типами данных
Измерение размера разных типов с memory_get_usage
Функция memory_get_usage() возвращает текущее выделение памяти. Измерение разницы до и после создания переменной даёт приблизительный размер, но учёт внутренних структур сложен.
$before = memory_get_usage();
$int = 1000;
$after = memory_get_usage();
echo "Разница: " . ($after - $before) . " bytes\n";
$before = memory_get_usage();
$float = 3.14159265358979;
$after = memory_get_usage();
echo "Разница для float: " . ($after - $before) . " bytes\n";
$before = memory_get_usage();
$string = "a" . str_repeat("b", 100);
$after = memory_get_usage();
echo "Разница для строки (101 сим): " . ($after - $before) . " bytes\n";
$before = memory_get_usage();
$largeArray = range(1, 1000);
$after = memory_get_usage();
echo "Разница для массива на 1000 элементов: " . ($after - $before) . " bytes\n";
Результат (пример на 64-битной системе):
Разница: 48 bytes Разница для float: 48 bytes Разница для строки (101 сим): 200 bytes Разница для массива на 1000 элементов: 59176 bytes
Сравнение размера разных типов массивов
Массивы с одинаковым количеством элементов, но разными типами значений, занимают разный объём.
function arrayMemory($array) {
$before = memory_get_usage();
$tmp = $array; // копия?
$after = memory_get_usage();
return $after - $before;
}
$intArray = range(1, 100);
$floatArray = array_map(function($n) { return $n * 1.5; }, range(1, 100));
$stringArray = array_map(function($n) { return "value_$n"; }, range(1, 100));
echo "Массив int: " . arrayMemory($intArray) . " bytes\n";
echo "Массив float: " . arrayMemory($floatArray) . " bytes\n";
echo "Массив string: " . arrayMemory($stringArray) . " bytes\n";
Результат (пример):
Массив int: 7640 bytes Массив float: 7640 bytes Массив string: 10976 bytes
Размер объекта с разным количеством свойств
Создание объекта с одним свойством и с десятью.
class SimpleClass {
public $prop1;
}
class TenProps {
public $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10;
}
$obj1 = new SimpleClass();
$obj1->prop1 = 42;
$obj2 = new TenProps();
for ($i = 1; $i <= 10; $i++) {
$obj2->{"p$i"} = $i * 10;
}
echo "Объект с 1 свойством: " . strlen(serialize($obj1)) . " (сериализация)\n";
echo "Объект с 10 свойствами: " . strlen(serialize($obj2)) . " (сериализация)\n";
Результат:
Объект с 1 свойством: 35 (сериализация) Объект с 10 свойствами: 137 (сериализация)
Влияние ссылок на размер массива
Массив, содержащий ссылки на другие переменные, может занимать меньше памяти, так как не копирует данные.
$bigString = str_repeat('x', 100000);
$before = memory_get_usage();
$arrayWithReference = [&$bigString];
$after = memory_get_usage();
echo "Массив со ссылкой: " . ($after - $before) . " bytes\n";
$before = memory_get_usage();
$arrayWithCopy = [$bigString];
$after = memory_get_usage();
echo "Массив с копией: " . ($after - $before) . " bytes\n";
Результат:
Массив со ссылкой: 136 bytes Массив с копией: 100280 bytes