Перейти к основному содержимому

Работа со скалярными типами в 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. Строка может быть пустой ("" или '') или содержать любой набор символов.

Способы записи строк

  1. Одинарные кавычки ('...'):

    • Не интерпретируют переменные и большинство escape-последовательностей.
    • Единственные допустимые escape-символы: \\ и \'.
    echo 'It\'s a string'; // It's a string
    echo 'Hello $name'; // Hello $name
  2. Двойные кавычки ("..."):

    • Интерполируют переменные и поддерживают escape-последовательности (\n, \t, \$, \", \\ и др.).
    $name = "Timur";
    echo "Hello $name\n"; // Hello Timur + новая строка
    echo "Price: \$10"; // Price: $10
  3. Heredoc (<<<IDENTIFIER ... IDENTIFIER):

    • Позволяет писать многострочные строки с интерполяцией, как в двойных кавычках.
    $text = <<<EOT
    This is a multi-line
    string with $variable interpolation.
    EOT;
  4. 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
truetrue11.0"1"
falsefalse00.0""
0false00.0"0"
42true4242.0"42"
0.0false00.0"0"
3.14true33.14"3.14"
""false00.0""
"0"false00.0"0"
"42"true4242.0"42"
"hello"true00.0"hello"

💡 Совет
Всегда используйте строгое сравнение (===, !==) там, где важен тип. Это предотвращает неожиданные срабатывания условий.


Рекомендации по работе со скалярными типами

  1. Включайте строгую типизацию в новых проектах:

    declare(strict_types=1);

    Это заставляет PHP проверять типы аргументов и возвращаемых значений.

  2. Избегайте слабых сравнений (==, !=) при работе с пользовательским вводом, API или критичными данными.

  3. Валидируйте входные данные явно:

    if (!is_string($input) || !ctype_digit($input)) {
    throw new InvalidArgumentException('Expected numeric string');
    }
  4. Используйте filter_var() для безопасного преобразования и валидации:

    $int = filter_var($input, FILTER_VALIDATE_INT);
    if ($int === false) { /* ошибка */ }
  5. Будьте осторожны с empty() и isset(): они решают разные задачи. empty() проверяет «falsy», isset() — существование и ненулевость.

  6. Для денежных расчётов не используйте 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" == falsetrue
  • "00" == "0"true
  • "0" == 0true
  • "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
0falsetrue
""falsetrue
" "0true
"1"truetrue
"abc"0true
"0e123"0true
"0x10"16true

📌 Внимание
Строка "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 === falsefalse.

Примеры:

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

Освоение главы0%