Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Junior: питання на співбесіді з теми «Типи й помилки»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

4 питання

=== (тотожність) - true, лише якщо однакові і значення, і тип. == (рівність) спершу приводить операнди до спільного типу, а тоді порівнює.

1 === '1';    // false - int і string
1 == '1';     // true
0 == 'abc';   // false у PHP 8, true у PHP 7
null == false; // true
'1e3' == '1000'; // true - обидва числові рядки

Що змінив PHP 8: порівняння числа з нечисловим рядком тепер порівнює їх як рядки. Раніше 0 == 'abc' було true, бо 'abc' перетворювався на 0 - джерело реальних вразливостей у перевірках паролів і токенів.

Правило: за замовчуванням ===. == - лише коли приведення типів свідомо потрібне, і тоді краще привести явно: (int) $request->input('page') === 1.

Ще пастки ==:

  • in_array($value, $list) і array_search за замовчуванням порівнюють через ==. Третій аргумент true вмикає строге порівняння.
  • switch теж порівнює через ==; match - через ===.

Докладніше в документації: Оператори порівняння

У PHP дві гілки «кидабельних» об'єктів, і обидві реалізують інтерфейс Throwable:

  • Exception - очікувані ситуації, які код програми кидає сам і може обробити: немає файлу, сервіс не відповів, дані не пройшли перевірку.
  • Error - помилки в самому коді чи середовищі, які кидає рушій: TypeError, ArgumentCountError, DivisionByZeroError, виклик методу на null.
try {
    $user->profile->avatar(); // $user->profile === null
} catch (Exception $e) {
    // сюди не потрапить: це Error
} catch (Error $e) {
    // Call to a member function avatar() on null
}

Що з цим робити:

  • Ловіть конкретні класи винятків, які очікуєте: catch (ConnectionException $e).
  • catch (Throwable $e) - лише на самому верху: в обробнику помилок фреймворку, у воркері черги, щоб записати збій і не впасти цілком.
  • Error зазвичай не «обробляють», а виправляють: це баг, і його треба побачити в логах, а не проковтнути.

До PHP 7 більшість таких помилок були фатальними й не ловилися взагалі - Error з'явився саме для того, щоб їх можна було перехопити.

Докладніше в документації: Помилки в PHP 7+

  • $a ?? $b (null coalescing) - повертає $a, якщо воно існує і не null, інакше $b. Не кидає попереджень на неіснуючих змінних і ключах.
  • $a ?: $b (скорочений тернарний, «elvis») - повертає $a, якщо воно істинне, інакше $b. Для 0, '', '0', [], false теж поверне $b.
$page = $_GET['page'] ?? 1;      // ключа немає - 1, без попередження
$page = $_GET['page'] ?: 1;      // ключа немає - попередження "Undefined array key"

$discount = 0;
$discount ?? 10;    // 0  - нуль не null
$discount ?: 10;    // 10 - нуль хибний

$title = '';
$title ?? 'Без назви';   // ''
$title ?: 'Без назви';   // 'Без назви'

Як обирати:

  • ?? - «значення за замовчуванням, якщо нічого немає»: ключі масиву, необов'язкові параметри, конфігурація. Найчастіший випадок.
  • ?: - коли порожній рядок, нуль чи порожній масив справді треба замінити: показати «Без назви» замість порожнього заголовка.

Присвоєння з ??= (PHP 7.4):

$options['timeout'] ??= 30;   // присвоїти, лише якщо ключа немає чи там null

Ланцюжки: $a ?? $b ?? $c - перше значення, що не null. Разом із nullsafe-оператором: $user?->profile?->city ?? 'Невідомо'.

Докладніше в документації: Оператор null coalescing

match (PHP 8.0) - вираз, що повертає значення залежно від умови:

$label = match ($status) {
    'new', 'pending' => 'Очікує',
    'paid' => 'Оплачено',
    'cancelled' => 'Скасовано',
};

Відмінності від switch:

  • Строге порівняння ===. switch порівнює через ==, тож switch ('1') спрацює на case 1, а switch (0) у PHP 7 - навіть на case 'abc'.
  • Повертає значення - його можна присвоїти чи повернути одразу. switch - інструкція.
  • Немає провалювання (fall-through) і не потрібен break. Забутий break у switch - класичний баг.
  • Необроблене значення - виняток UnhandledMatchError. switch без default просто нічого не робить, і помилка залишається непомітною.
  • Кілька умов через кому в одній гілці.

match (true) - заміна ланцюжку if/elseif з довільними умовами:

$grade = match (true) {
    $score >= 90 => 'A',
    $score >= 75 => 'B',
    $score >= 60 => 'C',
    default => 'F',
};

Обмеження: у кожній гілці - один вираз. Якщо гілці потрібно кілька інструкцій, - викликати метод або лишити if/switch.

У поєднанні з enum match без default - спосіб гарантувати, що кожен варіант оброблено: новий case без гілки дасть UnhandledMatchError, а статичний аналізатор (PHPStan) попередить ще до запуску.

Докладніше в документації: match