Работа со скалярными типами в PHP
Работа со скалярными типами в PHP
PHP — язык с динамической типизацией, но это не означает отсутствие типов. Наоборот, в PHP существует чёткая система типов, и скалярные типы составляют её фундаментальную основу. Скалярные типы представляют собой простейшие значения, которые не содержат внутренней структуры: они атомарны и не могут быть разложены на более мелкие составляющие в рамках языка.
Основы скалярных типов в PHP
Скалярный тип — это примитивный тип данных, хранящий одно значение без внутренней структуры. В отличие от массивов или объектов, скалярные значения не имеют свойств, методов или индексов. Они используются для представления логических состояний, чисел и текста.
PHP поддерживает четыре скалярных типа:
boolean— логический тип, принимающий значенияtrueилиfalse.integer— целое число, положительное, отрицательное или ноль.float(также называемыйdouble) — число с плавающей точкой, используется для представления дробных значений.string— последовательность байтов, интерпретируемая как текст в заданной кодировке (обычно UTF-8).
Начиная с PHP 7.0, язык поддерживает строгую типизацию (declare(strict_types=1);), что позволяет контролировать передачу значений определённых типов в функции и методы. Однако вне контекста строгой типизации PHP активно применяет неявные преобразования типов, что требует особого внимания при работе со скалярными значениями.
Логический тип: boolean
boolean — это тип данных, предназначенный для представления логических значений. Он принимает ровно два возможных значения: true и false.
Представление и литералы
В PHP литералы true и false записываются строчными буквами:
$isReady = true;
$hasError = false;
Эти значения не зависят от регистра при присвоении, но принято использовать именно строчные формы для соответствия стандартам кодирования (PSR).
Приведение к boolean: «falsy» и «truthy» значения
PHP автоматически приводит любые значения к логическому типу в контекстах, где ожидается boolean: условные операторы (if, while), логические операции (&&, ||, !), тернарный оператор и т.д.
Следующие значения считаются «falsy» (приводятся к false):
false(логическое значение)0(целое число)0.0(число с плавающей точкой)"0"(строка, содержащая один символ'0')""(пустая строка)null- пустой массив
[]
Все остальные значения считаются «truthy» (приводятся к true), включая:
- любые ненулевые числа (
-1,42,3.14) - непустые строки (
"hello","00"," "— даже пробел!) - непустые массивы
- объекты любого класса
Пример:
var_dump((bool) ""); // bool(false)
var_dump((bool) "0"); // bool(false)
var_dump((bool) " "); // bool(true)
var spoofed = "00";
var_dump((bool) $spoofed); // bool(true)
⚠️ Предупреждение
Строка"0"— единственная непустая строка, которая приводится кfalse. Это частый источник ошибок, особенно при работе с пользовательским вводом или API.
Операторы и функции, возвращающие boolean
Многие операторы и функции в PHP возвращают логические значения:
- Сравнения:
==,===,<,>,<=,>= - Логические операторы:
&&,||,!,xor - Функции:
is_array(),file_exists(),empty(),isset()
Функция empty() проверяет, является ли значение «falsy», но не вызывает предупреждение, если переменная не определена:
if (empty($userInput)) {
echo "Поле не заполнено";
}
В отличие от этого, isset() проверяет, существует ли переменная и не равна ли она null.
Целочисленный тип: integer
integer представляет собой целое число в диапазоне, зависящем от архитектуры системы. На 64-битных системах максимальное значение составляет 9223372036854775807 (PHP_INT_MAX), минимальное — -9223372036854775808 (PHP_INT_MIN).
Литералы и запись
Целые числа можно записывать в различных системах счисления:
- Десятичная:
42,-17 - Шестнадцатеричная:
0x2A(эквивалентно 42) - Восьмеричная:
052(эквивалентно 42) - Двоичная:
0b101010(эквивалентно 42)
Начиная с PHP 7.4, поддерживаются разделители цифр для улучшения читаемости:
$largeNumber = 1_000_000; // эквивалентно 1000000
Переполнение и поведение
Если результат арифметической операции выходит за пределы допустимого диапазона, PHP автоматически преобразует значение в тип float:
$big = PHP_INT_MAX;
$result = $big + 1;
var_dump($result); // float(9.2233720368548E+18)
Это поведение может привести к потере точности, так как float не может точно представлять все целые числа за пределами 53-битной мантиссы.
Проверка и преобразование
Функция is_int() (или is_integer(), is_long()) проверяет, является ли значение целым числом без приведения:
is_int(42); // true
is_int("42"); // false
is_int(42.0); // false
Для преобразования других типов в integer используется приведение (int) или функция intval():
(int) "42"; // 42
(int) "42abc"; // 42 (остаток игнорируется)
(int) "abc42"; // 0
(int) true; // 1
(int) false; // 0
(int) 3.9; // 3 (дробная часть отбрасывается)
📌 Внимание
Преобразование строки в число останавливается при первом недопустимом символе. Это может привести к неожиданным результатам, если строка содержит смешанный контент.
Числа с плавающей точкой: float
float (или double) используется для представления вещественных чисел. В PHP этот тип реализован на основе стандарта IEEE 754 двойной точности (64-битный).
Литералы
Запись возможна в обычной или экспоненциальной форме:
$pi = 3.14159;
$avogadro = 6.022e23;
$small = 1.23E-4;
Точность и ограничения
Числа с плавающей точкой не являются точными для всех десятичных дробей. Например:
var_dump(0.1 + 0.2 == 0.3); // bool(false)
Причина — двоичное представление дробей. Поэтому никогда не сравнивайте float на точное равенство. Вместо этого используйте сравнение с допуском (epsilon):
function floatEquals($a, $b, $epsilon = 1e-10) {
return abs($a - $b) < $epsilon;
}
var_dump(floatEquals(0.1 + 0.2, 0.3)); // bool(true)
Функции для работы с float
is_float()— проверяет, является ли значение числом с плавающей точкой.floor(),ceil(),round()— округление.number_format()— форматирование числа для вывода.INF,-INF,NAN— специальные значения (бесконечность и не число).
Пример:
var_dump(is_finite(1.0 / 0)); // bool(false)
var_dump(is_nan(sqrt(-1))); // bool(true)
Преобразование в float
Приведение к float выполняется через (float) или floatval():
(float) "3.14"; // 3.14
(float) "3.14abc"; // 3.14
(float) "abc"; // 0.0
(float) true; // 1.0
Строковый тип: string
string — это последовательность байтов. PHP не накладывает ограничений на кодировку, но современные приложения почти всегда используют UTF-8. Строка может быть пустой ("" или '') или содержать любой набор символов.
Способы записи строк
-
Одинарные кавычки (
'...'):- Не интерпретируют переменные и большинство escape-последовательностей.
- Единственные допустимые escape-символы:
\\и\'.
echo 'It\'s a string'; // It's a string
echo 'Hello $name'; // Hello $name -
Двойные кавычки (
"..."):- Интерполируют переменные и поддерживают escape-последовательности (
\n,\t,\$,\",\\и др.).
$name = "Timur";
echo "Hello $name\n"; // Hello Timur + новая строка
echo "Price: \$10"; // Price: $10 - Интерполируют переменные и поддерживают escape-последовательности (
-
Heredoc (
<<<IDENTIFIER ... IDENTIFIER):- Позволяет писать многострочные строки с интерполяцией, как в двойных кавычках.
$text = <<<EOT
This is a multi-line
string with $variable interpolation.
EOT; -
Nowdoc (
<<<'IDENTIFIER' ... IDENTIFIER):- Аналог heredoc, но без интерполяции (как одинарные кавычки).
Длина и доступ к символам
Длина строки определяется функцией strlen() (возвращает количество байтов, а не символов!):
echo strlen("café"); // 5 (если в UTF-8: 'é' занимает 2 байта)
Для работы с Unicode-символами используйте mb_strlen(), mb_substr() и другие функции из расширения mbstring.
Доступ к символу по индексу:
$str = "Hello";
echo $str[1]; // 'e'
⚠️ Предупреждение
Индексация работает на уровне байтов, а не символов. В UTF-8 многобайтовые символы будут разорваны.
Конкатенация и операции
Основной оператор — точка (.):
$greeting = "Hello" . " " . "World"; // "Hello World"
Сокращённая форма: .=.
Строки можно сравнивать с помощью операторов (==, ===, <, >). Сравнение выполняется побайтово.
Преобразование в строку
Любое значение можно преобразовать в строку:
(string) 42; // "42"
(string) true; // "1"
(string) false; // ""
(string) null; // ""
(string) [1,2,3]; // TypeError (в PHP 8+), ранее — "Array"
Функция strval() делает то же самое.
Объекты могут определять собственное строковое представление через метод __toString():
class User {
public function __toString() {
return "User object";
}
}
echo new User(); // "User object"
Неявные преобразования между скалярными типами
PHP активно применяет неявные преобразования, особенно в операциях сравнения и арифметике. Это мощный, но опасный механизм.
Примеры неявных преобразований
"10" + 5; // 15 (строка → число)
"10 apples" + 5; // 15 (преобразуется только начальная часть)
true + 1; // 2 (true → 1)
"hello" + 1; // 1 ("hello" → 0)
"2" == 2; // true (слабое сравнение)
"2" === 2; // false (строгое сравнение)
Таблица преобразований (упрощённо)
| Исходный тип | → boolean | → integer | → float | → string |
|---|---|---|---|---|
true | true | 1 | 1.0 | "1" |
false | false | 0 | 0.0 | "" |
0 | false | 0 | 0.0 | "0" |
42 | true | 42 | 42.0 | "42" |
0.0 | false | 0 | 0.0 | "0" |
3.14 | true | 3 | 3.14 | "3.14" |
"" | false | 0 | 0.0 | "" |
"0" | false | 0 | 0.0 | "0" |
"42" | true | 42 | 42.0 | "42" |
"hello" | true | 0 | 0.0 | "hello" |
💡 Совет
Всегда используйте строгое сравнение (===,!==) там, где важен тип. Это предотвращает неожиданные срабатывания условий.
Рекомендации по работе со скалярными типами
-
Включайте строгую типизацию в новых проектах:
declare(strict_types=1);Это заставляет PHP проверять типы аргументов и возвращаемых значений.
-
Избегайте слабых сравнений (
==,!=) при работе с пользовательским вводом, API или критичными данными. -
Валидируйте входные данные явно:
if (!is_string($input) || !ctype_digit($input)) {
throw new InvalidArgumentException('Expected numeric string');
} -
Используйте
filter_var()для безопасного преобразования и валидации:$int = filter_var($input, FILTER_VALIDATE_INT);
if ($int === false) { /* ошибка */ } -
Будьте осторожны с
empty()иisset(): они решают разные задачи.empty()проверяет «falsy»,isset()— существование и ненулевость. -
Для денежных расчётов не используйте
float. Храните значения в целых единицах (например, копейках) или применяйте специализированные библиотеки (brick/money).
Сравнение скалярных типов
PHP предоставляет два основных способа сравнения значений: слабое (==, !=) и строгое (===, !==). Различие между ними критично при работе со скалярными типами.
Слабое сравнение (==)
При слабом сравнении PHP приводит оба операнда к общему типу, после чего сравнивает их значения. Это может привести к неожиданным результатам:
var_dump(0 == "0"); // true
var_dump(0 == false); // true
var_dump("10" == 10); // true
var_dump("1e3" == 1000); // true
var_dump("" == null); // true
Особенно опасны следующие случаи:
"0" == false→true"00" == "0"→true"0" == 0→true"0" == ""→false(разные строки)
Слабое сравнение полезно при обработке пользовательского ввода, где типы могут быть неизвестны, но требует осторожности.
Строгое сравнение (===)
Строгое сравнение проверяет значение и тип одновременно:
var_dump(0 === "0"); // false
var_dump(0 === false); // false
var_dump("10" === 10); // false
var_dump(42 === 42); // true
var_dump(true === true); // true
Это поведение предсказуемо и безопасно. В большинстве случаев рекомендуется использовать именно строгое сравнение.
Таблица эквивалентности для ==
Ниже приведены часто встречающиеся «ловушки» слабого сравнения:
| Левый операнд | Правый операнд | Результат |
|---|---|---|
0 | "0" | true |
0 | false | true |
"" | false | true |
" " | 0 | true |
"1" | true | true |
"abc" | 0 | true |
"0e123" | 0 | true |
"0x10" | 16 | true |
📌 Внимание
Строка"0e123"интерпретируется как число с плавающей точкой в экспоненциальной форме (0 * 10^123 = 0), поэтому она равна0.
Функции для работы со скалярными типами
PHP предоставляет набор встроенных функций для проверки и преобразования скалярных значений.
Проверка типа
| Функция | Описание |
|---|---|
is_bool($x) | Проверяет, является ли значение логическим |
is_int($x) | Проверяет, является ли значение целым числом |
is_float($x) | Проверяет, является ли значение float |
is_string($x) | Проверяет, является ли значение строкой |
is_numeric($x) | Проверяет, представляет ли значение число (включая строки вида "123", "1.5", "1e5") |
Примеры:
is_bool(true); // true
is_int("42"); // false
is_numeric("42"); // true
is_numeric("42abc"); // false
is_numeric("1e5"); // true
Преобразование типов
| Функция | Эквивалент приведения | Особенности |
|---|---|---|
boolval($x) | (bool) $x | Приведение к boolean |
intval($x) | (int) $x | Поддерживает основание системы счисления |
floatval($x) | (float) $x | |
strval($x) | (string) $x |
Функция intval() принимает второй аргумент — основание системы счисления:
intval("101", 2); // 5 (двоичное)
intval("FF", 16); // 255 (шестнадцатеричное)
Безопасное преобразование
Для валидации и безопасного преобразования используйте filter_var():
// Валидация целого числа
$int = filter_var("42", FILTER_VALIDATE_INT);
if ($int !== false) {
echo "Целое число: $int";
}
// Валидация email (для сравнения)
$email = filter_var("user@example.com", FILTER_VALIDATE_EMAIL);
// Преобразование с фильтрацией
$safeString = filter_var("<script>alert()</script>", FILTER_SANITIZE_STRING);
Особенности строкового представления чисел
PHP допускает несколько форм записи чисел внутри строк, которые автоматически преобразуются при арифметических операциях:
- Десятичные:
"42","-3.14" - Экспоненциальные:
"1e5","2.5E-3" - Шестнадцатеричные:
"0xFF"(только в контексте преобразования черезintval()или при явном указании основания)
Однако:
echo "0xFF" + 0; // 0 (не распознаётся как число!)
echo intval("0xFF", 16); // 255
Строки, начинающиеся с 0x, не считаются числами функцией is_numeric():
is_numeric("0xFF"); // false
is_numeric("255"); // true
Работа с null и скалярными типами
Хотя null не является скалярным типом, он часто взаимодействует со скалярными значениями.
nullприводится кfalseв логическом контексте.- При преобразовании в строку даёт пустую строку.
- При преобразовании в число даёт
0. - Строгое сравнение:
null === false→false.
Примеры:
var_dump((bool) null); // false
var_dump((string) null); // ""
var_dump((int) null); // 0
var_dump(null == 0); // true
var_dump(null === 0); // false
Для проверки на null используйте is_null() или оператор ===.
Типизация в функциях (начиная с PHP 7)
PHP поддерживает объявление типов параметров и возвращаемых значений:
function add(int $a, int $b): int {
return $a + $b;
}
function greet(string $name): string {
return "Hello, $name";
}
function isActive(bool $flag): bool {
return $flag;
}
По умолчанию действует слабая типизация: если передать строку "42" в функцию с параметром int, PHP автоматически преобразует её в 42.
Чтобы запретить такое поведение, включите строгую типизацию:
<?php
declare(strict_types=1);
function add(int $a, int $b): int {
return $a + $b;
}
add("42", 1); // TypeError!
Строгая типизация применяется только к файлу, в котором объявлена. Она не влияет на вызовы из других файлов без declare(strict_types=1).
Примеры
Пример 1: Безопасное чтение параметра из запроса
$id = $_GET['id'] ?? null;
if (!is_numeric($id) || (string)(int)$id !== (string)$id) {
throw new InvalidArgumentException('ID must be a positive integer');
}
$id = (int)$id;
Пример 2: Сравнение с учётом типа
function isValidStatus($status): bool {
return in_array($status, ['active', 'inactive', 'pending'], true);
}
// Использование строгого сравнения в in_array (третий параметр = true)
Пример 3: Работа с булевыми флагами из строки
function parseBool(string $value): bool {
return match(strtolower(trim($value))) {
'1', 'true', 'on', 'yes' => true,
'0', 'false', 'off', 'no' => false,
default => throw new InvalidArgumentException("Invalid boolean value: $value")
};
}
parseBool("TRUE"); // true
parseBool("off"); // false