PHP: переменные и типы
PHP является языком с динамической типизацией, что означает возможность автоматического преобразования типов во время выполнения. Такое поведение часто приводит к неожиданным результатам. Для повышения надёжности кода применяется строгая типизация. В этом разделе рассматриваются основные приёмы работы с переменными и типами, а также способы контроля типов.
Строгая типизация с declare(strict_types=1)
Как включить строгую типизацию в PHP?
Самый эффективный способ обеспечить контроль типов - использовать директиву declare(strict_types=1) в начале файла. Она заставляет PHP строго соблюдать объявленные типы параметров и возвращаемых значений. Если передаётся значение несоответствующего типа, возникает ошибка TypeError.
<?php
declare(strict_types=1);
function sum(int $a, int $b): int {
return $a + $b;
}
echo sum(2, 3); // 5
echo sum(2.5, 3); // TypeError
?>
В первом вызове передаются целые числа, код выполняется успешно. Во втором - число с плавающей точкой, и PHP выбрасывает исключение, предотвращая неявное преобразование.
Как объявить функцию без строгой типизации?
Если declare(strict_types=1) отсутствует, PHP разрешает автоматическое приведение типов. Это может быть удобно при работе с внешними данными, но снижает надёжность.
<?php
function add(int $a, int $b) {
return $a + $b;
}
echo add('5', 10); // 15, строка '5' преобразована в int
?>
Второй вариант - использовать union types (доступно с PHP 8.0). Это позволяет явно указать несколько допустимых типов.
<?php
declare(strict_types=1);
function multiply(int|float $a, int|float $b): int|float {
return $a * $b;
}
echo multiply(2.5, 3); // 7.5
echo multiply(2, 3); // 6
?>
Типичные ошибки и их решения:
- Ошибка TypeError - возникает при нарушении типов в строгом режиме. Решение: проверить передаваемые значения на соответствие объявленным типам.
- Неявное преобразование - происходит при выключенном строгом режиме. Используйте строгий режим или проверяйте типы вручную.
- Путаница с операторами сравнения - оператор == приводит типы, а === сравнивает без приведения. Рекомендуется всегда использовать === для строгого сравнения.
Проверка и преобразование типов
Как определить тип переменной?
Основной способ - использование функций is_* (например, is_int, is_string) и gettype. Функции is_* возвращают логическое значение и безопасны для применения.
<?php
$value = 42;
if (is_int($value)) {
echo "Целое число";
} else {
echo "Тип: " . gettype($value);
}
?>
Как преобразовать тип переменной?
Явное преобразование выполняется с помощью операторов в скобках: (int), (float), (string) и других. Это полезно, когда необходимо гарантировать определённый тип перед операцией.
<?php
$number = "15.7";
$intNumber = (int) $number; // 15, дробная часть отбрасывается
$floatNumber = (float) $number; // 15.7
?>
Какие альтернативы проверки типов существуют?
Функция var_dump выводит полную информацию о типе и значении, удобна для отладки. Функция settype изменяет тип переменной на месте, но не рекомендуется из-за побочных эффектов.
<?php
$var = "123";
var_dump($var); // string(3) "123"
settype($var, "int");
echo $var; // 123
?>
Для проверки ввода пользователя лучше использовать filter_var с соответствующим флагом.
<?php
$input = "42";
if (filter_var($input, FILTER_VALIDATE_INT) !== false) {
echo "Целое число";
} else {
echo "Не число";
}
?>
Проблемы при работе с типами:
- Сравнение строки и числа - при использовании == строка может быть преобразована в число, что приводит к логическим ошибкам. Решение - использовать ===.
- Потеря данных при преобразовании - например, (int) от строки "12.5abc" даст 12, а "abc" даст 0. Решение - предварительная проверка is_numeric.
- Неопределённые переменные - обращение к необъявленной переменной вызывает warning. Используйте isset или ?? (null coalescing operator).
Расширенные примеры работы с типами
Как использовать union types с возвратом void?
<?php
declare(strict_types=1);
function processValue(int|string $value): void {
if (is_int($value)) {
echo "Целое: " . $value;
} else {
echo "Строка: " . $value;
}
}
processValue(42);
processValue("Hello");
?>
Целое: 42 Строка: Hello
Как преобразовать строку в число с учётом локали?
Используйте NumberFormatter из расширения intl для безопасного разбора локализованных чисел.
<?php
$locale = 'de_DE';
$formatter = new NumberFormatter($locale, NumberFormatter::DECIMAL);
$value = $formatter->parse('1.234,56');
echo $value; // 1234.56
?>
1234.56
Как проверить, является ли строка числом в заданной системе счисления?
Функция intval с указанием основания системы счисления позволяет преобразовывать строки в целые числа.
<?php
$hex = "1A";
$decimal = intval($hex, 16);
echo $decimal; // 26
$oct = "123";
echo intval($oct, 8); // 83, т.к. 1*64+2*8+3
?>
26 83
Как использовать match для проверки типа?
Конструкция match (PHP 8.0) может применяться для выполнения различных действий в зависимости от типа значения.
<?php
declare(strict_types=1);
function describe($value): string {
return match (true) {
is_int($value) => "Целое: $value",
is_string($value) => "Строка длиной " . strlen($value),
is_array($value) => "Массив из " . count($value) . " элементов",
default => "Неизвестный тип"
};
}
echo describe(100);
echo describe("PHP");
echo describe([1,2,3]);
?>
Целое: 100 Строка длиной 3 Массив из 3 элементов
Как принудительно преобразовать массив в объект и обратно?
Используйте (object) для массива и (array) для объекта. Полезно при работе с JSON.
<?php
$array = ["name" => "Alice", "age" => 30];
$object = (object) $array;
echo $object->name; // Alice
$back = (array) $object;
print_r($back);
?>
Alice
Array
(
[name] => Alice
[age] => 30
)