Знание PHP 8 на собесе это маркер «пишет на современном PHP». Спрашивают match, enum, readonly, атрибуты и что дал JIT.
match
$label = match ($status) {
'new', 'pending' => 'Ожидает',
'paid' => 'Оплачен',
default => throw new UnexpectedValueException($status),
};
Отличия от switch: это выражение, сравнение строгое (===), нет проваливания, без подходящей ветки и default бросается UnhandledMatchError. match (true) заменяет цепочку if/elseif.
enum (8.1)
enum OrderStatus: string
{
case New = 'new';
case Paid = 'paid';
case Cancelled = 'cancelled';
public function isFinal(): bool
{
return match ($this) {
self::Cancelled => true,
self::New, self::Paid => false,
};
}
}
OrderStatus::from('paid'); // вариант или ValueError
OrderStatus::tryFrom('x'); // null
OrderStatus::cases(); // все варианты
OrderStatus::Paid->value; // 'paid'
Варианты это синглтоны: сравнивают через ===. Перечисления могут иметь методы, константы и реализовывать интерфейсы, но не свойства с состоянием, наследование и new. Laravel (casts) и Doctrine (enumType) умеют хранить их в колонках.
readonly
final readonly class Money // readonly-класс (8.2)
{
public function __construct(public int $amount, public string $currency) {}
public function add(Money $o): self
{
return new self($this->amount + $o->amount, $this->currency);
}
}
Свойство записывается один раз и только изнутри класса, повторная запись бросает Error. Вложенные объекты остаются изменяемыми: readonly защищает ссылку, а не содержимое. Для изменённой копии создают новый объект (метод with...); с PHP 8.3 readonly-свойства можно переинициализировать в __clone.
Атрибуты
#[Route('/posts/{id}', methods: ['GET'])]
public function show(int $id): Response { ... }
Атрибуты это метаданные, которые читает код через рефлексию (ReflectionMethod::getAttributes()). Фреймворки делают это при сборке кеша. Полезные встроенные: #[\Override] (8.3) проверяет, что метод действительно переопределяет родительский, #[\SensitiveParameter] (8.2) скрывает значение в стектрейсах.
Другие новинки
- 8.0: union types, nullsafe
?->, именованные аргументы, продвижение свойств,str_contains,throwкак выражение, JIT. - 8.1:
never, пересечения типов, first-class callablef(...),newв инициализаторах, файберы,array_is_list. - 8.2: DNF-типы,
trueкак тип, динамические свойства объявлены устаревшими. - 8.3: типизированные константы классов,
json_validate,#[\Override]. - 8.4: property hooks и асимметричная видимость свойств.
JIT и файберы
JIT компилирует горячий байткод в машинный код поверх OPcache. Типичному веб-приложению, которое ждёт базу и сеть, он почти не помогает, а вычислениям помогает заметно.
Файбер это функция с собственным стеком, которую можно приостановить из любой глубины (Fiber::suspend()). Параллельности нет, это основа асинхронных библиотек вроде Revolt и AMPHP.
Частые ошибки
- Ждать от
matchнестрогого сравнения, как уswitch. - Считать readonly-объект глубоко неизменяемым.
- Хранить в базе порядковый номер варианта enum вместо строки.
- Рассчитывать, что JIT ускорит CRUD.
Что спросят на собесе
- Чем
matchотличается отswitch? - Как устроены
enum, чем backed отличается от pure? - Что гарантирует
readonlyи чего не гарантирует? - Что такое атрибуты и как их использует фреймворк?
- Что дал JIT и кому?