Строгая типизация в PHP 8: понятное руководство с примерами и ошибками
Зачем нужна строгая типизация в PHP 8
Ключевая проблема «слабого» PHP — неочевидные преобразования типов. PHP 8 привнёс зрелую типизацию: строгий режим, расширенные типы и типизированные свойства. Это повышает надёжность, делает код самодокументируемым и облегчает рефакторинг.
declare(strict_types=1): как включить строгий режим
Строгая типизация включается на уровне файла и должна стоять первой строчкой. В строгом режиме PHP не будет автоматически приводить типы аргументов функций и методов — вместо этого бросит TypeError.
<?php
declare(strict_types=1);
function add(int $a, int $b): int {
return $a + $b;
}
echo add(2, 3); // 5
echo add('2', '3'); // TypeError в strict-режиме, в слабом — вернуло бы 5
Важно: строгий режим действует только в текущем файле. Если вы подключаете файлы без declare(strict_types=1), их поведение останется «слабым».
Типы аргументов и возвращаемых значений
Базовые скалярные типы: int, float, string, bool. Также доступны array, object, callable, iterable, self, parent и static (для методов класса). Для возврата значения указывайте тип после двоеточия.
<?php
declare(strict_types=1);
function sanitizeName(?string $name): string {
// ?string означает: string|null
$name = $name ?? '';
return trim($name);
}
function average(array $numbers): float {
if ($numbers === []) {
return 0.0;
}
return array_sum($numbers) / count($numbers);
}
Советы:
- Старайтесь типизировать всё: параметры, возвращаемые значения и свойства.
- Используйте ?T только там, где реально допускаете null.
- Уточняйте возвращаемые типы — это облегчает тестирование и рефакторинг.
Union types (объединения) и nullable
Union types позволяют принять несколько вариантов типов. Для «может быть null» используйте короткую форму ?T, которая равна T|null.
<?php
declare(strict_types=1);
function findUser(int|string $id): array {
// Можно передать 42 или '42-uuid'
// ... запрос к БД или репозиторию
return ['id' => (string)$id, 'name' => 'Alice'];
}
function decode(?string $json): array {
if ($json === null || $json === '') {
return [];
}
$data = json_decode($json, true, flags: JSON_THROW_ON_ERROR);
return is_array($data) ? $data : [];
}
Когда полезно union types:
- API, где идентификатор бывает числовым или строковым (UUID).
- Миграции кода: постепенно сужайте типы, сохраняя обратную совместимость.
Типизированные свойства и readonly
Начиная с PHP 7.4 можно типизировать свойства, а с 8.1 — помечать их readonly (устанавливаются один раз). Это защита от случайной записи и отличный способ документировать модель данных.
<?php
declare(strict_types=1);
class User {
public int $id;
public readonly string $email;
public function __construct(int $id, string $email) {
$this->id = $id;
$this->email = strtolower($email);
}
}
$u = new User(1, 'TEST@MAIL.COM');
$u->id = 2; // ОК
$u->email = 'x@x'; // Error: cannot modify readonly property
Плюсы: меньше «магии», больше инвариантов и ранних ошибок на этапе разработки.
Специальные типы: mixed, never, static
- mixed — «любой тип». Используйте, если вход может быть чем угодно (например, внешний ввод). Постарайтесь как можно раньше сузить mixed до конкретного типа.
- never — функция не возвращается (например, делает redirect и завершает выполнение).
- static — для методов, возвращающих экземпляр текущего класса (флюентный интерфейс, наследование).
<?php
declare(strict_types=1);
function redirect(string $url): never {
header('Location: ' . $url);
exit; // гарантирует never
}
class Builder {
public function withId(int $id): static {
// ...
return $this; // static полезен при наследовании Builder
}
}
Частые ошибки и как их исправить
- Забыли declare(strict_types=1). Итог — скрытая коэрция. Решение: включайте строгий режим в каждом новом файле, добавьте проверку линтером/CI.
- Избыточный null. Не размножайте ?T без необходимости. Если параметр обязателен — делайте обязательным и валидируйте раньше.
- Слишком общий mixed. Вводите DTO/Value Object с типами вместо «массива всего».
- Неверная сигнатура интерфейсов. При переопределении методов наследники обязаны сохранять совместимую сигнатуру типов.
- Ловите TypeError там, где это нужно. В контроллерах или точке входа можно преобразовать исключение в понятный ответ API.
Практический чеклист по типизации
- В каждом файле: declare(strict_types=1).
- Типизируйте параметры и возвращаемые значения во всех публичных методах.
- Используйте union types там, где их ждут потребители API.
- Свойства — типизированные; для констант и неизменных полей — readonly.
- Выносите «сырой» ввод в слой валидации, внутрь домена передавайте уже строгие типы.
- Подключите статический анализ (PHPStan/Psalm) и повысите уровень строгости постепенно.
SEO-итог: типизация в PHP 8 на реальных примерах
Строгая типизация в PHP 8 — это не «мода», а способ писать надёжный и предсказуемый код. Начните с declare(strict_types=1), задайте типы в публичном API, примените union types и readonly-свойства — и количество багов из‑за «магического» приведения типов резко снизится.
Хотите быстро закрепить практику и закрыть пробелы? Попробуйте практический курс с заданиями и проектом: Прокачать PHP 8 и MySQL на реальных проектах (курс «с Нуля до Гуру 3.0»).
-
Создано 05.11.2025 17:01:20
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.