> Расскажите про типизацию в PHP (PHP)

Уровень: senior · Роль: backend · Язык: PHP · Категория: Технические вопросы

Компании: vanta

Стек: PHP

> Пример ответа

Короткий ответ

PHP - язык с динамической типизацией, но с 7-й версии активно развивается строгая типизация через декларации типов. Ключевые механизмы: type hints для параметров и возвращаемых значений, strict_types для контроля приведения, union types, nullable types, mixed, а также типизированные свойства классов. В PHP 8 появились intersection types, static return type и атрибуты для метаданных. На практике это даёт баланс между гибкостью динамики и безопасностью статики.

Подробное объяснение

Типизация в PHP прошла долгий путь: от полностью динамической в PHP 5 до гибридной в PHP 8.x. Основная идея - не заставлять разработчика указывать типы везде, но дать возможность явно контролировать контракты между функциями и классами.

Механизмы типизации:

  • Type hints - для параметров функций/методов и возвращаемых значений. Поддерживаются скалярные типы (int, float, string, bool), классы, интерфейсы, callable, iterable, object, mixed (PHP 8.0).
  • strict_types=1 - директива в начале файла, которая запрещает неявное приведение скалярных типов. Без неё PHP пытается привести значение (например, "123" → int 123), с ней - выбрасывает TypeError.
  • Union types (PHP 8.0) - параметр или возврат может принимать несколько типов: int|string.
  • Intersection types (PHP 8.1) - тип должен удовлетворять нескольким классам/интерфейсам: A&B.
  • Nullable types - ?Type или Type|null.
  • Типизированные свойства (PHP 7.4) - public int $count; с обязательной инициализацией или readonly.
  • Readonly свойства (PHP 8.1) - неизменяемые после инициализации.
  • mixed - любой тип, эквивалент отсутствия типа, но явный.
  • never (PHP 8.1) - функция не возвращает управление (exit, throw).
  • static (PHP 8.0) - возврат типа вызывающего класса (позднее статическое связывание).

Важный нюанс: strict_types действует только на вызовы из файла, где она объявлена. То есть если файл A вызывает функцию из файла B, то поведение приведения определяется директивой в файле A.

Типизация в PHP - это не статический анализ, а runtime-проверка. Она не ловит ошибки до выполнения, но гарантирует корректность в момент вызова. Для статического анализа используются инструменты вроде Psalm или PHPStan, которые работают поверх синтаксиса и аннотаций.

На практике

В реальных проектах типизация применяется для:

  • Контрактов между сервисами и репозиториями - каждый метод явно объявляет, что принимает и возвращает.
  • DTO и Value Objects - типизированные свойства защищают от "мусорных" данных.
  • API-слоёв - строгие типы предотвращают случайное приведение строк к числам.
  • Работы с коллекциями - generic-аннотации (@param User[] $users) для статических анализаторов, хотя runtime их не проверяет.

Рекомендации:

  • Всегда включать declare(strict_types=1) в новых файлах - это дисциплинирует и убирает неявные приведения.
  • Использовать union types вместо mixed там, где это возможно.
  • Для свойств классов - типизировать и инициализировать, избегая null без необходимости.
  • Для сложных структур (массив объектов) - комбинировать runtime-типы с PHPDoc для статических анализаторов.
  • Не злоупотреблять mixed - это фактически отказ от типизации.

Пример кода

PHP
<?php
declare(strict_types=1);
final class User
{
public function __construct(
public readonly int $id,
public readonly string $name,
public readonly ?string $email = null,
) {}
}
interface UserRepository
{
/** @return list<User> */
public function findByName(string $name): array;
public function findById(int $id): ?User;
}
final class UserService
{
public function __construct(
private UserRepository $repository,
) {}
public function getUserLabel(int|string $identifier): string
{
$user = is_int($identifier)
? $this->repository->findById($identifier)
: $this->repository->findByName($identifier)[0] ?? null;
if ($user === null) {
throw new RuntimeException('User not found');
}
return sprintf('%s (%d)', $user->name, $user->id);
}
}

Как отвечать на собеседовании

Начните с краткого определения: PHP - динамически типизированный язык с возможностью строгой типизации на уровне runtime. Затем перечислите ключевые механизмы в хронологическом порядке: PHP 7 - скалярные типы и strict_types, PHP 7.4 - типизированные свойства, PHP 8 - union types, mixed, static, PHP 8.1 - intersection types, readonly, never.

Обязательно упомяните разницу между strict_types=1 и поведением по умолчанию - это частый вопрос. Приведите пример: без strict_types "123" приведётся к int, с - выбросит TypeError.

Покажите понимание ограничений: типизация не проверяет структуру массивов, generic-типы не поддерживаются на уровне runtime, для статического анализа нужны Psalm/PHPStan. Это покажет зрелость мышления.

Если спросят про mixed - скажите, что это явный "любой тип", но лучше использовать union types, чтобы сохранить информацию для анализаторов.

Что проверяет интервьюер

  • Понимание разницы между динамической и статической типизацией в контексте PHP.
  • Знание конкретных синтаксических конструкций и их версий.
  • Понимание поведения strict_types и области её действия.
  • Умение объяснить trade-off между гибкостью и безопасностью.
  • Осведомлённость о смежных инструментах (PHPStan, Psalm) и их роли.

Типичные ошибки

  • Утверждение, что PHP - строго типизированный язык. Это не так: типизация опциональна и проверяется в runtime.
  • Путаница между strict_types и type hints - это разные вещи: hints - декларация, strict_types - режим приведения.
  • Забывают, что strict_types действует на файл вызова, а не на файл определения.
  • Использование mixed как "ленивого" решения без попытки сузить типы.
  • Незнание, что типизированные свойства требуют инициализации до чтения (иначе Error).
  • Утверждение, что PHP поддерживает generics - это не так, только аннотации для статических анализаторов.
  • Путаница между ?Type и Type|null - это одно и то же, но ?Type нельзя комбинировать с union types (нужно писать Type|null).

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью