Підготуйтеся до технічної співбесіди на PHP-розробника: сучасний PHP 8.x, Laravel, SQL, архітектура та робота з AI-інструментами. Питання поділено за рівнями Junior, Middle і Senior, до кожного — приклад відповіді.
== порівнює значення з приведенням типів, === — значення і тип без приведення. Наприклад, '1' == 1 дає true, а '1' === 1 — false.
У PHP 8 правила порівняння рядків із числами стали суворішими: 0 == 'abc' тепер false. На практиці краще завжди використовувати === і declare(strict_types=1), щоб уникнути несподіваних результатів.
JuniorPHP 8.x і ООП
Що таке інтерфейс і абстрактний клас? Коли що використовувати?
Приклад відповіді
Інтерфейс описує контракт — набір методів без реалізації, і клас може реалізувати кілька інтерфейсів. Абстрактний клас може містити спільний код і стан, але клас успадковує лише один такий клас.
Інтерфейс обирають, коли важлива можливість підмінити реалізацію (наприклад, PaymentGateway для різних платіжних систем). Абстрактний клас — коли кілька класів мають спільну логіку, яку не хочеться дублювати.
JuniorSQL і бази даних
Що таке SQL-ін'єкція і як від неї захиститися?
Приклад відповіді
Це атака, коли дані користувача потрапляють у SQL-запит як частина коду. Наприклад, рядок ' OR 1=1 -- у полі логіну може обійти перевірку.
Захист — підготовлені запити (prepared statements) з параметрами через PDO або query builder / Eloquent, які роблять це автоматично. Ніколи не склеюйте SQL із вхідних даних, а для назв колонок у сортуванні використовуйте білий список.
JuniorLaravel
Що таке міграції в Laravel і навіщо вони потрібні?
Приклад відповіді
Міграції — це версіоновані PHP-файли, які описують зміни структури бази даних: створення таблиць, колонок, індексів. Вони зберігаються в Git разом із кодом.
Завдяки міграціям кожен розробник і кожен сервер отримують однакову схему БД командою php artisan migrate, а зміни можна відкотити через migrate:rollback.
JuniorPHP: основи мови
Які типи даних є в PHP? Чим відрізняються прості типи від складених?
Простий тип зберігає одне значення, складений — набір значень або структуру. Масиви в PHP копіюються при присвоєнні (copy-on-write), а об'єкти передаються за «дескриптором»: дві змінні вказують на той самий об'єкт.
JuniorPHP: основи мови
Які відмінності між одинарними та подвійними лапками в PHP?
Приклад відповіді
В одинарних лапках рядок береться майже буквально: змінні не підставляються, працюють лише \' і \\. У подвійних лапках підставляються змінні ("Привіт, $name", "{$user->name}") і спецсимволи \n, \t.
Для довгих текстів є heredoc (як подвійні лапки) і nowdoc (як одинарні). Різниця в швидкодії мізерна — обирають за зручністю.
JuniorPHP: основи мови
Що таке приведення типів? Які неявні перетворення типів існують у PHP?
Приклад відповіді
Явне приведення — (int) $x, (string) $x, intval(). Неявне відбувається автоматично: у арифметиці ('5' + 3 дає 8), при порівнянні через ==, у логічному контексті (if ($x)), при конкатенації чисел із рядками.
У PHP 8 правила стали суворішими: 'abc' + 1 кидає TypeError, а 0 == 'abc' тепер false. Щоб уникати сюрпризів, використовують declare(strict_types=1) і ===.
JuniorPHP: основи мови
Яка різниця між null, false і 0?
Приклад відповіді
null означає відсутність значення, false — логічне «ні», 0 — число нуль. Це три різні типи, але в логічному контексті всі вони хибні, і null == false == 0 при нестрогому порівнянні.
Саме тому функції на кшталт strpos() перевіряють через === false: позиція 0 — це знайдений рядок на початку, а не помилка.
JuniorPHP: основи мови
У чому різниця між isset(), empty() та is_null()?
Приклад відповіді
isset($x) — змінна існує і не дорівнює null; не видає попередження для неіснуючих змінних і ключів;
empty($x) — змінна не існує або «порожня»: '', 0, '0', [], null, false;
is_null($x) — значення дорівнює null; для неіснуючої змінної видасть попередження.
Пастка empty(): рядок '0' вважається порожнім, тому для форм краще перевіряти явно.
JuniorPHP: основи мови
Що таке масив у PHP? Чим індексований масив відрізняється від асоціативного?
Приклад відповіді
Масив у PHP — упорядкована хеш-таблиця «ключ → значення». В індексованому масиві ключі — цілі числа ([10, 20, 30]), в асоціативному — рядки (['name' => 'Олена', 'age' => 25]).
Технічно це одна структура, тому ключі можна змішувати. Масиви зберігають порядок додавання елементів. Для перевірки, що масив — «список» з ключами 0..n-1, є array_is_list() (PHP 8.1).
JuniorPHP: основи мови
Як перевірити, чи існує елемент у масиві?
Приклад відповіді
За ключем: array_key_exists('email', $data) або isset($data['email']). Різниця: isset поверне false, якщо ключ є, але значення null;
за значенням: in_array($value, $array, true) — третій параметр вмикає строге порівняння;
позицію значення повертає array_search().
Для частих перевірок у великому масиві швидше перевернути його через array_flip() і шукати за ключем.
JuniorPHP: основи мови
Чим відрізняються array_map(), array_filter() та array_reduce()?
Приклад відповіді
array_map перетворює кожен елемент і повертає масив тієї самої довжини;
array_filter лишає елементи, для яких колбек повернув true (ключі зберігаються — часто потрібен array_values);
array_reduce згортає масив до одного значення, наприклад суми.
У чому різниця між foreach, for, while та do-while?
Приклад відповіді
foreach перебирає масиви й ітеровані об'єкти — найзручніший для колекцій. for — коли потрібен лічильник і відома кількість ітерацій. while перевіряє умову до кожної ітерації, do-while — після, тому виконується хоча б один раз.
У foreach із посиланням (foreach ($arr as &$v)) після циклу треба робити unset($v), інакше наступний цикл може зіпсувати останній елемент.
JuniorPHP: основи мови
Чим відрізняються оператори break і continue?
Приклад відповіді
break повністю виходить із циклу (або switch), continue пропускає решту поточної ітерації й переходить до наступної.
Обидва приймають число рівнів для вкладених циклів: break 2 виходить із двох циклів одразу. Але глибока вкладеність — сигнал, що код варто винести у функцію з return.
JuniorPHP: основи мови
Що таке інкремент і декремент? Чим відрізняються префіксна та постфіксна форми?
Приклад відповіді
++ збільшує значення на 1, -- зменшує. Префіксна форма ++$a спочатку змінює змінну, потім повертає нове значення. Постфіксна $a++ повертає старе значення, а потім змінює змінну.
Що таке рекурсія? Наведіть приклад її використання.
Приклад відповіді
Рекурсія — коли функція викликає саму себе з меншою задачею, доки не дійде до базового випадку. Типові приклади — обхід дерева категорій, вкладених меню, файлової системи.
function countItems(array $tree): int {
$count = 0;
foreach ($tree as $node) {
$count += 1 + countItems($node['children'] ?? []);
}
return $count;
}
Без базового випадку рекурсія нескінченна; дуже глибока рекурсія може вичерпати стек — тоді краще ітеративний підхід.
JuniorPHP: основи мови
Що таке функція? Як передавати аргументи за значенням і за посиланням?
Приклад відповіді
Функція — іменований блок коду, який приймає аргументи й повертає результат. За замовчуванням аргументи передаються за значенням: функція працює з копією, оригінал не змінюється.
За посиланням — через &: function addItem(array &$cart, $item) { $cart[] = $item; } змінює оригінальний масив. Посилання ускладнюють розуміння коду, тому частіше повертають новий результат. Об'єкти й так не копіюються — функція може змінити їхні властивості.
JuniorPHP: основи мови
Що таке аргументи за замовчуванням і іменовані аргументи?
Приклад відповіді
Аргумент за замовчуванням має значення, якщо його не передали: function greet(string $name = 'Гість'). Необов'язкові параметри ставлять після обов'язкових.
Іменовані аргументи (PHP 8.0) дають змогу передати значення за назвою параметра в будь-якому порядку й пропустити необов'язкові:
htmlspecialchars($text, double_encode: false);
Це робить виклики з багатьма параметрами зрозумілішими.
JuniorPHP: основи мови
Що таке типізація параметрів і тип повернення функції?
Приклад відповіді
Типи вказують, які значення приймає й повертає функція: function total(array $items): float. PHP перевіряє їх під час виконання й кидає TypeError при невідповідності.
Без strict_types скалярні значення приводяться (рядок '5' стане 5 для int), з declare(strict_types=1) — ні. Типи роблять код самодокументованим і допомагають IDE та статичному аналізу (PHPStan).
JuniorPHP: основи мови
Що означають типи mixed, void, never та static у контексті типізації PHP?
Приклад відповіді
mixed — будь-яке значення, включно з null;
void — функція нічого не повертає;
never (PHP 8.1) — функція ніколи не завершується нормально: завжди кидає виняток або викликає exit;
static як тип повернення — повертається екземпляр того класу, на якому викликали метод (корисно для fluent-інтерфейсів і наслідування).
JuniorPHP: основи мови
Що таке nullable-типи та union types?
Приклад відповіді
Nullable-тип дозволяє null: ?string означає «рядок або null». Union types (PHP 8.0) дозволяють кілька типів: int|float, string|null.
У PHP 8.1 з'явилися intersection types (Countable&Iterator — об'єкт реалізує обидва інтерфейси), а в 8.2 — DNF-типи на кшталт (A&B)|null.
JuniorPHP: основи мови
Як працюють оператори ??, ?: і nullsafe-оператор ?->?
Приклад відповіді
$a ?? $b — повертає $a, якщо воно існує й не null, інакше $b; не видає попередження для неіснуючого ключа;
$a ?: $b — повертає $a, якщо воно «істинне», інакше $b (тобто 0 і '' теж замінюються);
$user?->getAddress()?->city — якщо щось у ланцюжку null, весь вираз повертає null без помилки.
Є також ??=: $config['lang'] ??= 'uk';.
JuniorPHP: основи мови
Що поверне функція, якщо в ній не вказати return?
Приклад відповіді
Функція поверне null. Якщо в неї оголошено тип повернення void, це очікувана поведінка.
Але якщо вказано, наприклад, : int, а return немає на якомусь шляху виконання, буде TypeError. Статичний аналіз (PHPStan) знаходить такі місця ще до запуску.
JuniorPHP: основи мови
Як працюють include, require, include_once та require_once?
Приклад відповіді
Усі підключають і виконують інший PHP-файл. Різниця в поведінці при помилці: include видає попередження й продовжує роботу, require зупиняє скрипт фатальною помилкою.
Варіанти _once підключають файл лише один раз, навіть якщо викликати кілька разів. У сучасних проєктах класи завантажуються автоматично через Composer, і ручні require лишаються хіба що для конфігурації та точки входу.
JuniorPHP: основи мови
Чим відрізняються echo, print і var_dump()?
Приклад відповіді
echo — мовна конструкція для виведення одного чи кількох рядків, нічого не повертає. print виводить один рядок і повертає 1, тому його можна використати у виразі.
var_dump() виводить тип і значення змінної з усією структурою — для налагодження. Для читабельного виведення масивів є print_r(), а в Laravel — dump() і dd().
JuniorPHP: основи мови
Які суперглобальні змінні є в PHP? Для чого використовують $_GET, $_POST, $_SERVER, $_SESSION і $_COOKIE?
Приклад відповіді
Суперглобальні змінні доступні в будь-якому місці коду:
$_GET — параметри з рядка запиту (?page=2);
$_POST — дані форми, надіслані методом POST;
$_SERVER — інформація про запит і сервер (метод, URI, заголовки, IP);
$_SESSION — дані сесії користувача (після session_start());
$_COOKIE — cookies, які надіслав браузер.
Також є $_FILES, $_ENV, $_REQUEST. Усі вхідні дані потрібно валідувати — їх контролює користувач. У фреймворках замість них використовують об'єкт Request.
JuniorPHP: основи мови
Що таке регулярні вирази? Наведіть приклад їх використання.
Приклад відповіді
Регулярний вираз — шаблон для пошуку й перевірки тексту. У PHP — функції preg_match, preg_replace, preg_split.
// перевірка українського номера телефону
if (preg_match('/^\+380\d{9}$/', $phone)) { ... }
// прибрати все, крім цифр
$digits = preg_replace('/\D+/', '', $input);
Для email краще filter_var($email, FILTER_VALIDATE_EMAIL), ніж власний складний вираз. Для UTF-8 тексту потрібен модифікатор u.
JuniorPHP: основи мови
Що таке генератори? Як працює оператор yield?
Приклад відповіді
Генератор — функція з yield, яка повертає значення по одному й призупиняється до наступного запиту. Значення обчислюються ліниво, тому генератор не тримає всі дані в пам'яті.
function readLines(string $file): Generator {
$h = fopen($file, 'r');
while (($line = fgets($h)) !== false) {
yield $line;
}
fclose($h);
}
foreach (readLines('big.csv') as $line) { ... }
Так можна обробити файл на гігабайти з мінімальним споживанням пам'яті. У Laravel схожу ідею реалізують lazy() і cursor().
JuniorPHP: основи мови
Що таке замикання (closure)? Для чого використовують use?
Приклад відповіді
Замикання — анонімна функція, яку можна зберегти в змінну й передати як аргумент. Зовнішні змінні вона не бачить автоматично — їх передають через use:
$min = 100;
$filtered = array_filter($prices, function ($p) use ($min) {
return $p >= $min;
});
use копіює значення на момент створення; use (&$x) передає за посиланням. Стрілкові функції fn($p) => $p >= $min захоплюють зовнішні змінні автоматично.
JuniorPHP: основи мови
Що таке простори імен (namespace)? Як працюють use та псевдоніми класів?
Приклад відповіді
Простори імен групують класи й запобігають конфліктам назв: App\Models\User і Vendor\Package\User можуть існувати разом.
use App\Models\User; дає змогу писати коротко User, а псевдонім вирішує конфлікт: use Vendor\Package\User as VendorUser;. Простір імен зазвичай відповідає структурі папок — на цьому побудоване автозавантаження PSR-4.
JuniorPHP: основи мови
Що таке автозавантаження класів? Для чого потрібен PSR-4?
Приклад відповіді
Автозавантаження підключає файл класу автоматично при першому зверненні до класу — не потрібно писати require для кожного файлу.
PSR-4 — стандарт відповідності простору імен і шляху до файлу: App\Services\Payment → app/Services/Payment.php. Composer генерує автозавантажувач за налаштуваннями в composer.json, а після додавання нового простору імен виконують composer dump-autoload.
JuniorPHP: основи мови
Які нововведення PHP 8.x ви знаєте?
Приклад відповіді
8.0: named arguments, union types, match, nullsafe ?->, constructor property promotion, атрибути, JIT;
На співбесіді важливіше показати, що ви реально використовуєте з цього списку.
JuniorPHP: основи мови
Що таке обробка помилок і винятків? Як працюють try, catch, finally і throw?
Приклад відповіді
Виняток кидають через throw, коли код не може продовжити роботу. try обгортає небезпечний код, catch перехоплює винятки певного типу, finally виконується завжди — для звільнення ресурсів.
У PHP 8 більшість фатальних помилок стали винятками класу Error; спільний інтерфейс — Throwable. Не варто «ковтати» винятки порожнім catch.
JuniorPHP 8.x і ООП
Що таке клас, об'єкт, властивість і метод?
Приклад відповіді
Клас — шаблон, що описує дані й поведінку. Об'єкт — конкретний екземпляр класу, створений через new. Властивість — змінна всередині об'єкта (дані), метод — функція, що описує дію.
Наприклад, клас Order має властивості $total і $status, метод pay(), а $order = new Order() — конкретне замовлення.
JuniorPHP 8.x і ООП
Що таке конструктор і деструктор? Коли вони викликаються?
Приклад відповіді
Конструктор __construct() викликається при створенні об'єкта — там ініціалізують властивості й отримують залежності. У PHP 8 є constructor property promotion: public function __construct(private UserRepository $users) {}.
Деструктор __destruct() викликається, коли на об'єкт не лишилося посилань або завершується скрипт. Використовується рідко — для звільнення ресурсів.
JuniorPHP 8.x і ООП
Які модифікатори доступу є в PHP? Чим відрізняються public, protected і private?
Приклад відповіді
public — доступно звідусіль;
protected — у самому класі та його нащадках;
private — лише всередині класу, де оголошено.
За замовчуванням варто робити властивості private і відкривати лише потрібне через методи. У PHP 8.4 з'явилася асиметрична видимість: public private(set) string $name — читати можна всім, змінювати лише всередині класу.
JuniorPHP 8.x і ООП
Що таке наслідування? Як воно працює в PHP?
Приклад відповіді
Наслідування дає змогу створити клас на основі іншого через extends: дочірній клас отримує публічні й захищені властивості та методи батьківського і може їх перевизначити.
PHP підтримує лише одиночне наслідування класів. Батьківський метод можна викликати через parent::method(), а final забороняє наслідування класу чи перевизначення методу. Глибоких ієрархій краще уникати — часто доречніша композиція.
JuniorPHP 8.x і ООП
Що таке інкапсуляція? Наведіть приклад.
Приклад відповіді
Інкапсуляція — приховування внутрішнього стану об'єкта й надання доступу лише через методи, які гарантують коректність даних.
class Wallet {
private int $balance = 0;
public function withdraw(int $amount): void {
if ($amount > $this->balance) {
throw new DomainException('Недостатньо коштів');
}
$this->balance -= $amount;
}
}
Баланс неможливо зробити від'ємним ззовні — усі правила зосереджені в одному місці.
JuniorPHP 8.x і ООП
Що таке поліморфізм? Наведіть приклад.
Приклад відповіді
Поліморфізм — можливість працювати з об'єктами різних класів через спільний інтерфейс, не знаючи конкретного класу.
interface Notifier { public function send(string $msg): void; }
class EmailNotifier implements Notifier { ... }
class TelegramNotifier implements Notifier { ... }
function notifyAll(array $notifiers, string $msg) {
foreach ($notifiers as $n) $n->send($msg);
}
Функції байдуже, як саме надсилається повідомлення, — додати новий канал можна без зміни наявного коду.
JuniorPHP 8.x і ООП
Що таке абстракція в ООП?
Приклад відповіді
Абстракція — виділення суттєвого й приховування деталей реалізації. Користувач класу знає, що робить метод, але не як.
Наприклад, метод $mailer->send($message) приховує SMTP-з'єднання, шаблони й повтори. В PHP абстракцію виражають через інтерфейси й абстрактні класи.
JuniorPHP 8.x і ООП
Чи може абстрактний клас мати приватні методи та реалізовані методи?
Приклад відповіді
Так. Абстрактний клас може містити звичайні реалізовані методи (публічні, захищені, приватні), властивості та конструктор, а також абстрактні методи без тіла, які мають реалізувати нащадки.
Приватні методи доступні лише в самому абстрактному класі — нащадки їх не бачать. Сам абстрактний метод не може бути приватним, бо нащадок мусить його реалізувати.
JuniorPHP 8.x і ООП
Що таке перевизначення методу? Чим воно відрізняється від перевантаження?
Приклад відповіді
Перевизначення (overriding) — дочірній клас оголошує метод із тією самою назвою і сумісною сигнатурою, змінюючи поведінку батьківського. У PHP 8.3 можна позначити його атрибутом #[\Override], щоб помилка в назві одразу виявилася.
Перевантаження (overloading) у класичному сенсі — кілька методів з однаковою назвою й різними параметрами — PHP не підтримує. Схожого ефекту досягають необов'язковими параметрами, union types або магічним __call().
JuniorPHP 8.x і ООП
Що таке статичні властивості й методи? Коли доречно використовувати static?
Приклад відповіді
Статичні члени належать класу, а не об'єкту: Math::round(), self::$count. Їх викликають без створення екземпляра.
Доречно для чистих допоміжних функцій без стану та фабричних методів (Money::fromCents(100)). Статичний змінюваний стан — по суті глобальна змінна: його важко тестувати й підмінювати, тому залежності краще передавати через конструктор.
JuniorPHP 8.x і ООП
Що таке пізнє статичне зв'язування? Як працює static:: порівняно з self::?
Приклад відповіді
self:: завжди посилається на клас, у якому написано код. static:: — на клас, через який метод реально викликали (пізнє статичне зв'язування).
class Model {
public static function create(): static { return new static(); }
}
class User extends Model {}
User::create(); // поверне User, а з new self() — Model
На цьому побудовано багато методів Eloquent, як-от User::query().
JuniorPHP 8.x і ООП
Що таке магічні методи PHP? Наведіть приклади __construct(), __get(), __set() і __toString().
Приклад відповіді
Магічні методи PHP викликає автоматично в певних ситуаціях:
__construct() — при створенні об'єкта;
__get($name) / __set($name, $value) — при читанні чи записі недоступної властивості (так Eloquent дає $user->email);
__toString() — коли об'єкт використовують як рядок;
також __call, __callStatic, __invoke, __clone.
Зловживати ними не варто: IDE і статичний аналіз гірше розуміють «магічний» код.
JuniorPHP 8.x і ООП
Що таке traits? Для чого вони потрібні?
Приклад відповіді
Trait — набір методів і властивостей, який можна «вставити» в кілька класів через use. Це спосіб повторно використати код без наслідування, бо клас може мати лише одного батька.
У Laravel трейти використовують постійно: HasFactory, SoftDeletes, Notifiable. Але трейт із великою кількістю логіки й залежностей ускладнює розуміння класу — часто краще виділити окремий сервіс.
JuniorPHP 8.x і ООП
Що відбувається, якщо два traits містять методи з однаковими іменами?
Приклад відповіді
Виникне фатальна помилка конфлікту, якщо його явно не вирішити. Для цього є insteadof і as:
class Report {
use CsvExport, PdfExport {
CsvExport::export insteadof PdfExport;
PdfExport::export as exportPdf;
}
}
Якщо метод із такою назвою оголошено в самому класі, він має пріоритет над методами трейтів.
JuniorPHP 8.x і ООП
Чи можна використовувати приватні методи trait у класі, який його підключає?
Приклад відповіді
Так. Методи трейта копіюються в клас, тому приватні методи трейта стають приватними методами самого класу й доступні всередині нього.
Видимість можна змінити при підключенні: use Helpers { format as public; }.
JuniorPHP 8.x і ООП
Чи можна підключати traits один до одного?
Приклад відповіді
Так, трейт може використовувати інші трейти через use всередині себе. Клас, який підключить такий трейт, отримає методи всіх вкладених.
При цьому важливо не створювати заплутаних ланцюжків — складно зрозуміти, звідки в класі взявся метод.
JuniorPHP 8.x і ООП
Що таке залежність між класами? Як зменшити сильне зв'язування?
Приклад відповіді
Клас залежить від іншого, якщо використовує його для роботи. Сильне зв'язування — коли клас сам створює залежність (new StripeClient()) і прив'язаний до конкретної реалізації: його важко тестувати й змінювати.
Зменшують через: передачу залежностей у конструктор, залежність від інтерфейсів, а не від класів, принцип єдиної відповідальності та події для слабкого зв'язку між модулями.
JuniorPHP 8.x і ООП
Що таке композиція? Чим вона відрізняється від наслідування?
Приклад відповіді
Наслідування — відношення «є» (AdminUser є User). Композиція — «має»: об'єкт містить інші об'єкти й делегує їм роботу (OrderService має PaymentGateway і Mailer).
Композиція гнучкіша: залежності можна замінити, комбінувати й тестувати окремо, тоді як зміна батьківського класу ламає всіх нащадків. Тому поширене правило — «надавайте перевагу композиції над наслідуванням».
JuniorPHP 8.x і ООП
Що таке принципи SOLID? Поясніть хоча б два з них на прикладах.
Приклад відповіді
S — Single Responsibility: клас має одну причину для змін. Контролер не має одночасно валідувати, рахувати знижки й надсилати листи;
O — Open/Closed: розширення без зміни коду — новий спосіб доставки через новий клас, а не новий if;
L — Liskov Substitution: нащадок має коректно замінювати батька;
I — Interface Segregation: маленькі інтерфейси замість одного величезного;
D — Dependency Inversion: залежність від абстракцій (PaymentGateway), а не від конкретних класів.
Краще пояснювати на прикладі зі свого коду.
JuniorPHP 8.x і ООП
Що таке Dependency Injection? Чим ін'єкція через конструктор відрізняється від ін'єкції через метод?
Приклад відповіді
Dependency Injection — клас не створює залежності сам, а отримує їх ззовні. Це спрощує тестування й заміну реалізацій.
Через конструктор передають обов'язкові залежності, потрібні всьому класу — об'єкт одразу готовий до роботи. Через метод — залежність, потрібну лише одній дії: у Laravel public function store(Request $request, OrderService $orders). Контейнер Laravel підставляє обидва варіанти автоматично.
JuniorPHP 8.x і ООП
Що таке Singleton? Які недоліки має цей патерн?
Приклад відповіді
Singleton гарантує, що клас має лише один екземпляр із глобальною точкою доступу (Database::getInstance()).
Недоліки: прихована глобальна залежність, складність тестування (неможливо підмінити), спільний стан між тестами. Сьогодні замість класичного Singleton використовують контейнер залежностей: $this->app->singleton(...) дає один екземпляр, але його все одно впроваджують явно.
JuniorPHP 8.x і ООП
Що таке шаблони проєктування? Які патерни ви знаєте та де їх використовували?
Приклад відповіді
Шаблони проєктування — перевірені рішення типових задач. Поширені в PHP-проєктах:
Strategy — різні способи доставки чи оплати за спільним інтерфейсом;
Factory — створення об'єктів залежно від умов;
Repository — доступ до даних за інтерфейсом;
Observer — події та слухачі в Laravel;
Decorator — додати кешування чи логування до сервісу без зміни його коду;
Adapter — обгортка над стороннім API.
На співбесіді цінують приклад, де патерн вирішив конкретну проблему, а не перелік назв.
JuniorHTTP, веб і безпека
Як браузер взаємодіє із сервером під час відкриття вебсторінки?
Приклад відповіді
браузер визначає IP-адресу домену через DNS;
встановлює TCP-з'єднання і для HTTPS — TLS-рукостискання;
вебсервер (Nginx) передає запит у PHP-FPM, застосунок формує відповідь;
браузер отримує HTML, розбирає його й довантажує CSS, JS, зображення, потім рендерить сторінку.
Кешування (браузер, CDN) може пропустити частину кроків.
JuniorHTTP, веб і безпека
У чому різниця між HTTP і HTTPS?
Приклад відповіді
HTTPS — це HTTP поверх TLS: дані шифруються, а сертифікат підтверджує, що ви спілкуєтеся саме з цим сайтом. Через HTTP паролі й cookies передаються відкритим текстом і їх можна перехопити.
Сьогодні HTTPS — стандарт для всіх сайтів: браузери позначають HTTP як небезпечний, а безкоштовні сертифікати видає Let's Encrypt. Також варто вмикати заголовок HSTS.
JuniorHTTP, веб і безпека
Які HTTP-методи ви знаєте? Чим відрізняються GET, POST, PUT, PATCH і DELETE?
Приклад відповіді
GET — отримати дані, не змінює стан сервера; параметри в URL, можна кешувати;
POST — створити ресурс або виконати дію; дані в тілі запиту;
PUT — повністю замінити ресурс;
PATCH — частково оновити ресурс;
DELETE — видалити ресурс.
GET, PUT і DELETE за специфікацією ідемпотентні: повтор не змінює результат. POST — ні, тому повторна відправка форми може створити дублікат.
JuniorHTTP, веб і безпека
Що означають HTTP-статуси 200, 201, 301, 302, 400, 401, 403, 404, 422 і 500?
Приклад відповіді
200 OK — успіх; 201 Created — ресурс створено;
301 — постійний редирект (важливо для SEO), 302 — тимчасовий;
400 Bad Request — некоректний запит;
401 Unauthorized — потрібна автентифікація;
403 Forbidden — користувач відомий, але прав немає;
404 Not Found — ресурс не знайдено;
422 Unprocessable Content — помилки валідації (Laravel повертає його для форм і API);
500 — помилка на сервері.
JuniorHTTP, веб і безпека
Чим відрізняються автентифікація та авторизація?
Приклад відповіді
Автентифікація відповідає на питання «хто ви?» — перевірка логіна й пароля, токена, входу через Google. Авторизація — «що вам дозволено?» — чи може цей користувач редагувати цю статтю.
Спочатку автентифікація, потім авторизація. У Laravel за першу відповідає Auth і guards, за другу — Gates і Policies.
JuniorHTTP, веб і безпека
Що таке сесія? Де зазвичай зберігаються її дані та як вона працює?
Приклад відповіді
HTTP не зберігає стан між запитами, тому сервер створює сесію: генерує ідентифікатор, надсилає його браузеру в cookie, а дані зберігає у себе. При наступному запиті браузер повертає cookie, і сервер знаходить дані сесії.
Дані зберігають у файлах, БД або Redis. Для кількох серверів підходить лише спільне сховище (Redis, БД). Після входу ідентифікатор сесії регенерують, щоб запобігти session fixation.
JuniorHTTP, веб і безпека
Що таке cookies? Які дані не варто зберігати в них?
Приклад відповіді
Cookies — невеликі дані (до ~4 КБ), які браузер зберігає й надсилає з кожним запитом на домен. Використовують для ідентифікатора сесії, налаштувань мови, «запам'ятати мене».
Не зберігають паролі, персональні дані, права доступу у відкритому вигляді — користувач може їх прочитати й змінити. Важливі прапорці: HttpOnly (недоступна з JavaScript), Secure (лише HTTPS), SameSite (захист від CSRF).
JuniorHTTP, веб і безпека
Чим відрізняються cookies, сесії та localStorage?
Приклад відповіді
Cookies зберігаються в браузері й автоматично надсилаються на сервер з кожним запитом;
сесія зберігається на сервері, а в браузері лише її ідентифікатор у cookie;
localStorage — сховище в браузері до ~5 МБ, на сервер автоматично не надсилається, доступне з JavaScript.
Токени доступу безпечніше тримати в HttpOnly cookie, ніж у localStorage, бо XSS-атака може прочитати localStorage.
JuniorHTTP, веб і безпека
Що таке REST API? Які його основні принципи?
Приклад відповіді
REST — стиль побудови API, де все є ресурсами з адресами (/api/orders/15), а дії виражаються HTTP-методами.
Принципи: відсутність стану між запитами (кожен запит містить усе потрібне, наприклад токен), єдиний інтерфейс (методи й статуси HTTP), кешованість відповідей, клієнт і сервер незалежні. На практиці також: іменники в множині в URL, JSON, правильні статуси, пагінація й версіонування (/api/v1).
JuniorHTTP, веб і безпека
Що таке JSON? Як перетворити масив PHP на JSON і навпаки?
Приклад відповіді
JSON — текстовий формат обміну даними з об'єктами, масивами, рядками, числами, true/false і null.
JSON_UNESCAPED_UNICODE зберігає кирилицю читабельною, другий параметр true повертає асоціативний масив замість об'єкта, а JSON_THROW_ON_ERROR кидає виняток замість тихого null при помилці.
JuniorHTTP, веб і безпека
Що таке XSS і CSRF? Як запобігти цим атакам?
Приклад відповіді
XSS — впровадження шкідливого JavaScript на сторінку через дані користувача (коментар зі <script>). Захист: екранування виводу (htmlspecialchars, {{ }} у Blade), Content-Security-Policy, HttpOnly cookies.
CSRF — сторонній сайт змушує браузер залогіненого користувача надіслати запит на ваш сайт. Захист: CSRF-токен у кожній формі (@csrf у Laravel), cookies з SameSite, і зміна даних лише через POST/PUT/DELETE.
JuniorHTTP, веб і безпека
Що таке CORS? Чому браузер може блокувати HTTP-запит?
Приклад відповіді
Браузер за замовчуванням забороняє JavaScript читати відповіді з іншого домену (same-origin policy). CORS — механізм, через який сервер дозволяє певним доменам доступ заголовками Access-Control-Allow-Origin тощо.
Для нестандартних запитів (з Authorization, JSON, методами PUT/DELETE) браузер спочатку надсилає preflight-запит OPTIONS. Якщо сервер не відповів потрібними заголовками, запит блокується. Важливо: CORS обмежує лише браузер, а не захищає API від інших клієнтів.
JuniorHTTP, веб і безпека
Чим відрізняються параметри запиту від параметрів маршруту?
Приклад відповіді
Параметр маршруту — частина шляху, що ідентифікує ресурс: /users/15, де 15 — {id}. Параметри запиту — після ?, для фільтрації, сортування, пагінації: /users?role=admin&page=2.
Правило: те, що визначає «який ресурс», — у маршруті, а «як показати» — у query-параметрах.
JuniorHTTP, веб і безпека
Що таке кешування? Які дані доцільно кешувати у вебзастосунку?
Приклад відповіді
Кешування — збереження результату дорогої операції, щоб не обчислювати його повторно. Рівні: браузер і CDN (статика, сторінки), застосунок (Redis), база даних.
Кешують дані, які часто читають і рідко змінюють: довідники, налаштування, лічильники, результати важких запитів, відповіді зовнішніх API. Головна складність — інвалідація: кеш треба очищати при зміні даних або задавати розумний час життя.
JuniorHTTP, веб і безпека
Що відбувається, коли сервер повертає помилку 500? Як шукати її причину?
Приклад відповіді
500 означає необроблену помилку на сервері: виняток у коді, фатальна помилка PHP, проблема з БД чи конфігурацією.
Порядок пошуку: логи застосунку (storage/logs/laravel.log), логи PHP-FPM і Nginx, сервіс моніторингу помилок (Sentry, Flare). Перевірити останні зміни й деплой, права на папки storage і bootstrap/cache, змінні оточення, доступність БД. На продакшні APP_DEBUG має бути вимкнено, щоб користувач не бачив деталей помилки.
JuniorSQL і бази даних
Що таке реляційна база даних? Які таблиці, рядки та стовпці вона містить?
Приклад відповіді
Реляційна БД зберігає дані в таблицях, пов'язаних між собою ключами. Таблиця описує сутність (users, orders), стовпці — її атрибути з типами (email VARCHAR, created_at TIMESTAMP), рядки — окремі записи.
Запити пишуть мовою SQL. Популярні СУБД: MySQL, PostgreSQL, MariaDB, SQLite.
JuniorSQL і бази даних
Що таке первинний ключ і зовнішній ключ?
Приклад відповіді
Первинний ключ (PRIMARY KEY) однозначно ідентифікує рядок у таблиці: унікальний і не NULL, зазвичай id. Зовнішній ключ (FOREIGN KEY) — стовпець, що посилається на первинний ключ іншої таблиці: orders.user_id → users.id.
Зовнішній ключ гарантує цілісність: не можна створити замовлення для неіснуючого користувача.
JuniorSQL і бази даних
Чим відрізняються PRIMARY KEY, UNIQUE та INDEX?
Приклад відповіді
PRIMARY KEY — головний ідентифікатор: унікальний, без NULL, один на таблицю;
UNIQUE — унікальність значень (наприклад, email), таких обмежень може бути кілька, у більшості СУБД дозволяє NULL;
INDEX — пришвидшує пошук і сортування, але не вимагає унікальності.
PRIMARY KEY і UNIQUE автоматично створюють індекс.
JuniorSQL і бази даних
Які типи зв'язків між таблицями існують?
Приклад відповіді
Один до одного: користувач і його профіль;
один до багатьох: користувач і його замовлення;
багато до багатьох: товари й категорії, студенти й курси.
Зв'язки реалізують зовнішніми ключами, а «багато до багатьох» — через проміжну таблицю.
JuniorSQL і бази даних
Як реалізувати зв'язки один до одного, один до багатьох і багато до багатьох?
Приклад відповіді
Один до одного: зовнішній ключ з унікальним обмеженням — profiles.user_id UNIQUE;
один до багатьох: зовнішній ключ на боці «багатьох» — orders.user_id;
багато до багатьох: проміжна таблиця product_category (product_id, category_id) зі складеним первинним або унікальним ключем.
У проміжній таблиці можна зберігати додаткові дані зв'язку, наприклад role_user.assigned_at.
JuniorSQL і бази даних
Що таке нормалізація бази даних? Навіщо вона потрібна?
Приклад відповіді
Нормалізація — організація таблиць так, щоб уникнути дублювання даних і аномалій при зміні. Наприклад, назву міста зберігають один раз у таблиці cities, а в users — лише city_id.
Без нормалізації зміна назви потребує оновлення тисяч рядків, і дані легко розходяться. На практиці зазвичай достатньо третьої нормальної форми.
JuniorSQL і бази даних
Що таке денормалізація та коли вона може бути корисною?
Приклад відповіді
Денормалізація — свідоме дублювання даних заради швидкості читання. Наприклад, зберігати orders_count у таблиці users замість підрахунку щоразу, або назву товару в рядку замовлення.
Доречно для частих важких запитів, звітів, а також коли потрібна «історична» копія (ціна товару на момент покупки). Ціна — потреба підтримувати узгодженість дубльованих даних.
JuniorSQL і бази даних
Чим відрізняються INNER JOIN, LEFT JOIN і RIGHT JOIN?
Приклад відповіді
INNER JOIN повертає лише рядки, для яких є збіг в обох таблицях;
LEFT JOIN повертає всі рядки лівої таблиці, а для відсутніх збігів — NULL у полях правої;
RIGHT JOIN — навпаки, всі рядки правої таблиці.
Наприклад, щоб показати всіх користувачів, навіть без замовлень, потрібен users LEFT JOIN orders. RIGHT JOIN використовують рідко — його зазвичай переписують як LEFT JOIN.
JuniorSQL і бази даних
Чим відрізняються JOIN і UNION?
Приклад відповіді
JOIN об'єднує таблиці «горизонтально»: додає стовпці з іншої таблиці за умовою зв'язку. UNION — «вертикально»: склеює результати кількох запитів з однаковою кількістю й типами стовпців.
UNION прибирає дублікати, UNION ALL — ні і працює швидше.
JuniorSQL і бази даних
Для чого потрібні WHERE, GROUP BY і HAVING?
Приклад відповіді
WHERE фільтрує рядки до групування, GROUP BY групує рядки для агрегатних функцій, HAVING фільтрує вже згруповані результати.
SELECT user_id, COUNT(*) AS orders
FROM orders
WHERE status = 'paid'
GROUP BY user_id
HAVING COUNT(*) > 5;
У WHERE не можна використати агрегатну функцію — для цього і є HAVING.
JuniorSQL і бази даних
Чим відрізняються COUNT(), SUM(), AVG(), MIN() і MAX()?
Приклад відповіді
Це агрегатні функції: COUNT — кількість рядків, SUM — сума значень, AVG — середнє, MIN і MAX — найменше й найбільше значення.
COUNT(*) рахує всі рядки, а COUNT(column) — лише ті, де значення не NULL. Решта функцій теж ігнорують NULL, тому AVG може відрізнятися від очікуваного.
JuniorSQL і бази даних
Що робить оператор DISTINCT?
Приклад відповіді
DISTINCT прибирає повторювані рядки з результату: SELECT DISTINCT city FROM users поверне кожне місто один раз. Можна використати в агрегаті: COUNT(DISTINCT user_id).
Якщо DISTINCT доводиться додавати, щоб «прибрати дублікати після JOIN», часто це ознака помилки в умові з'єднання.
JuniorSQL і бази даних
Що таке підзапит (subquery)? Коли його використовують?
Приклад відповіді
Підзапит — запит усередині іншого запиту: у WHERE, FROM або SELECT.
SELECT * FROM products
WHERE price > (SELECT AVG(price) FROM products);
Використовують для порівняння з агрегатом, перевірки існування (WHERE EXISTS (...)), побудови проміжних результатів. Часто той самий результат можна отримати через JOIN — оптимізатор сучасних СУБД добре справляється з обома варіантами, але варто перевіряти через EXPLAIN.
JuniorSQL і бази даних
Чим відрізняються DELETE, TRUNCATE та DROP?
Приклад відповіді
DELETE видаляє рядки за умовою, працює в транзакції, запускає тригери;
TRUNCATE швидко очищає всю таблицю і скидає автоінкремент; у MySQL не відкочується в транзакції;
DROP видаляє саму таблицю разом зі структурою.
DELETE без WHERE видалить усі рядки — тому на продакшні такі запити виконують дуже обережно.
JuniorSQL і бази даних
Що таке транзакція? Поясніть принципи ACID.
Приклад відповіді
Транзакція — група операцій, яка виконується повністю або не виконується зовсім. Наприклад, створення замовлення й списання товару зі складу.
Atomicity (атомарність) — усе або нічого;
Consistency (узгодженість) — дані лишаються коректними щодо обмежень;
Isolation (ізольованість) — паралельні транзакції не бачать проміжних змін одна одної;
Durability (довговічність) — після коміту зміни не зникнуть навіть при збої.
JuniorSQL і бази даних
Що таке індекс бази даних? Як він впливає на SELECT, INSERT і UPDATE?
Приклад відповіді
Індекс — окрема структура (зазвичай B-дерево), яка дозволяє швидко знаходити рядки без повного сканування таблиці, як предметний покажчик у книзі.
SELECT із фільтром чи сортуванням за індексованим полем стає значно швидшим. Але INSERT, UPDATE і DELETE сповільнюються, бо треба оновлювати й індекси, а самі індекси займають місце. Тому індекси створюють під реальні запити, а не на кожне поле.
JuniorSQL і бази даних
Що таке складений індекс? Чому важливий порядок його стовпців?
Приклад відповіді
Складений індекс будується за кількома стовпцями: INDEX (status, created_at). Він працює за принципом лівого префікса: допоможе запитам з умовою за status або за status і created_at, але не запиту лише за created_at.
Зазвичай першими ставлять стовпці з умовою рівності, а потім — для діапазонів і сортування.
JuniorSQL і бази даних
Як знайти причину повільного SQL-запиту?
Приклад відповіді
Знайти повільні запити: slow query log, Laravel Telescope, Debugbar;
подивитися план через EXPLAIN: чи використовується індекс, скільки рядків переглядається;
перевірити, чи вибираються лише потрібні стовпці й рядки (SELECT *, відсутність LIMIT);
пошукати N+1 у коді;
додати або змінити індекс і порівняти час до й після.
Важливо тестувати на обсязі даних, наближеному до продакшну.
JuniorSQL і бази даних
Для чого використовують EXPLAIN?
Приклад відповіді
EXPLAIN показує план виконання запиту: в якому порядку читаються таблиці, які індекси використовуються, скільки рядків доведеться переглянути.
Тривожні сигнали в MySQL: type: ALL (повне сканування), великі значення rows, Using filesort і Using temporary у великих таблицях. EXPLAIN ANALYZE реально виконує запит і показує фактичний час.
JuniorSQL і бази даних
Що таке зовнішні ключі та каскадне видалення?
Приклад відповіді
Зовнішній ключ пов'язує таблиці й не дає посилатися на неіснуючі записи. Поведінку при видаленні батьківського запису задають опцією:
ON DELETE CASCADE — видалити й пов'язані записи (позиції замовлення разом із замовленням);
ON DELETE SET NULL — обнулити посилання;
RESTRICT — заборонити видалення, поки є пов'язані записи.
Каскад зручний, але небезпечний: одне видалення може непомітно прибрати багато даних.
JuniorSQL і бази даних
Чим відрізняються DATETIME і TIMESTAMP у MySQL?
Приклад відповіді
TIMESTAMP зберігає момент часу в UTC і перетворює його з урахуванням часового поясу з'єднання; діапазон обмежено 1970–2038 роками. DATETIME зберігає дату й час «як є», без перетворень, з діапазоном до 9999 року.
Поширена практика — зберігати все в UTC і конвертувати в часовий пояс користувача під час виведення.
JuniorSQL і бази даних
Які типи даних MySQL ви знаєте? Коли варто використовувати DECIMAL замість FLOAT?
Приклад відповіді
Основні: цілі (TINYINT, INT, BIGINT), дробові (DECIMAL, FLOAT, DOUBLE), рядки (VARCHAR, TEXT), дата й час (DATE, DATETIME, TIMESTAMP), JSON, ENUM, BOOLEAN (це TINYINT(1)).
FLOAT зберігає числа наближено, тому 0.1 + 0.2 не дорівнює точно 0.3. Для грошей і всього, що вимагає точності, використовують DECIMAL(10,2) або зберігають суму в копійках як ціле число.
JuniorSQL і бази даних
Чим відрізняються INNER JOIN і запит із підзапитом?
Приклад відповіді
Обидва можуть дати однаковий результат. JOIN зручний, коли потрібні стовпці з обох таблиць. Підзапит — коли друга таблиця потрібна лише для фільтрації (WHERE id IN (...) або EXISTS).
Важлива різниця: JOIN з таблицею «багатьох» може продублювати рядки, а EXISTS — ні. Щодо швидкодії, сучасні оптимізатори часто перетворюють одне на інше, тому вирішує EXPLAIN, а не загальне правило.
JuniorSQL і бази даних
Що таке блокування рядків? Для чого потрібен SELECT ... FOR UPDATE?
Приклад відповіді
Блокування не дає іншим транзакціям змінювати рядок, поки поточна транзакція з ним працює. SELECT ... FOR UPDATE читає рядок і блокує його до кінця транзакції: інші транзакції, що хочуть його змінити, чекатимуть.
Використовують, коли рішення залежить від прочитаного значення: перевірити залишок на складі й зменшити його. У Laravel — ->lockForUpdate() усередині DB::transaction().
JuniorSQL і бази даних
Як запобігти ситуації, коли два користувачі одночасно змінюють один запис?
Приклад відповіді
Песимістичне блокування: SELECT ... FOR UPDATE у транзакції;
оптимістичне блокування: стовпець version або updated_at, і оновлення лише якщо версія не змінилася (UPDATE ... WHERE id = ? AND version = ?); якщо оновлено 0 рядків — конфлікт, показуємо користувачу;
атомарні операції: UPDATE products SET stock = stock - 1 WHERE id = ? AND stock > 0.
Вибір залежить від того, наскільки часті конфлікти.
JuniorSQL і бази даних
Що таке міграції бази даних?
Приклад відповіді
Міграції — файли з описом змін структури БД (створити таблицю, додати колонку, індекс), які зберігаються в Git разом із кодом і застосовуються по черзі.
Завдяки ним схема однакова в усіх розробників і на серверах, а зміни можна переглянути на код-рев'ю. У Laravel: php artisan make:migration, migrate, migrate:rollback. Важливе правило: не змінювати вже застосовану на продакшні міграцію — створювати нову.
JuniorSQL і бази даних
Як спроєктувати таблиці для категорій із вкладеними підкатегоріями?
Приклад відповіді
Найпростіше — список суміжності: categories (id, name, parent_id), де parent_id посилається на ту саму таблицю, а NULL — коренева категорія. Повне дерево отримують рекурсивним запитом (WITH RECURSIVE у MySQL 8 і PostgreSQL).
Альтернативи для частих запитів «усі нащадки»: materialized path (path = '1/5/12') або nested set. Для невеликих довідників дерево часто просто кешують цілком.
JuniorSQL і бази даних
Чим відрізняються SQL і NoSQL? Які типи NoSQL-баз існують?
Приклад відповіді
SQL-бази зберігають дані в таблицях зі строгою схемою, підтримують JOIN і транзакції. NoSQL мають гнучкішу модель і часто простіше масштабуються горизонтально.
Типи NoSQL: ключ-значення (Redis), документні (MongoDB), колонкові (Cassandra, ClickHouse для аналітики), графові (Neo4j), пошукові (Elasticsearch). На практиці їх поєднують: основні дані — в PostgreSQL чи MySQL, кеш і черги — в Redis, пошук — в Elasticsearch.
JuniorSQL і бази даних
Що таке реплікація, партиціювання та шардинг?
Приклад відповіді
Реплікація — копіювання даних з основного сервера на репліки: читання можна розподілити між ними, а репліка підстрахує при збої;
партиціювання — поділ великої таблиці на частини в межах одного сервера, наприклад за місяцями;
шардинг — розподіл даних між різними серверами за ключем (наприклад, user_id).
Шардинг найскладніший: JOIN і транзакції між шардами важкі, тому до нього вдаються лише тоді, коли інші способи вичерпано.
JuniorSQL і бази даних
Що таке збережені процедури та тригери? Коли вони можуть бути корисними?
Приклад відповіді
Збережена процедура — програма на SQL усередині БД, яку викликають за назвою. Тригер — код, що автоматично виконується при INSERT, UPDATE чи DELETE.
Корисні для аудиту змін, підтримки денормалізованих лічильників, важких операцій над даними без пересилання в застосунок. Недоліки: бізнес-логіка «ховається» в БД, її складніше тестувати, версіонувати й налагоджувати, тому в більшості PHP-проєктів логіку тримають у коді.
JuniorLaravel
Що таке Laravel і які його основні переваги?
Приклад відповіді
Laravel — найпопулярніший PHP-фреймворк для вебзастосунків і API. Переваги: зрозумілий синтаксис, Eloquent ORM, міграції, черги, події, кешування, автентифікація «з коробки», зручне тестування й велика екосистема (Horizon, Sanctum, Livewire, Filament).
Також — велика спільнота й документація, тому типові задачі вже мають готові рішення.
JuniorLaravel
Що таке MVC? Як ця архітектура реалізована в Laravel?
Приклад відповіді
MVC ділить застосунок на три частини: Model — дані й бізнес-правила, View — відображення, Controller — приймає запит, викликає потрібну логіку й повертає відповідь.
У Laravel: моделі Eloquent у app/Models, шаблони Blade у resources/views, контролери в app/Http/Controllers. На практиці додають ще шари — сервіси, Form Request, API Resources, — щоб контролери лишалися тонкими.
JuniorLaravel
Як працює життєвий цикл HTTP-запиту в Laravel?
Приклад відповіді
Запит потрапляє в public/index.php, завантажується автозавантажувач і створюється застосунок;
реєструються та запускаються сервіс-провайдери;
HTTP-ядро пропускає запит через глобальні middleware;
маршрутизатор знаходить маршрут і застосовує його middleware;
викликається контролер або замикання, формується відповідь;
відповідь проходить middleware у зворотному напрямку й надсилається клієнту.
JuniorLaravel
Що таке маршрути? Де визначаються маршрути для вебсторінок та API?
Приклад відповіді
Маршрут зв'язує URL і HTTP-метод з обробником: Route::get('/orders/{order}', [OrderController::class, 'show']);.
Вебмаршрути — у routes/web.php (з сесіями, cookies, CSRF), API — у routes/api.php (без стану, з префіксом /api; у нових версіях файл створюється командою php artisan install:api). Переглянути всі маршрути: php artisan route:list.
JuniorLaravel
Чим відрізняються GET, POST, PUT, PATCH і DELETE у маршрутах Laravel?
Приклад відповіді
Відповідно до HTTP: Route::get — показати, post — створити, put/patch — оновити, delete — видалити. Route::resource('photos', PhotoController::class) створює всі сім стандартних маршрутів CRUD.
HTML-форми підтримують лише GET і POST, тому для PUT і DELETE у Blade додають @method('PUT') — Laravel підмінить метод.
JuniorLaravel
Що таке контролер? Яку логіку варто розміщувати в ньому?
Приклад відповіді
Контролер приймає HTTP-запит, викликає потрібну логіку й повертає відповідь. У ньому мають бути лише «координаційні» дії: отримати перевірені дані, викликати сервіс, повернути view чи JSON.
Валідацію виносять у Form Request, бізнес-логіку — у сервіси чи action-класи, форматування відповіді — в API Resources. Так контролер лишається коротким, а логіку можна перевикористати з консольних команд і черг.
JuniorLaravel
Що таке middleware? На якому етапі обробки запиту він виконується?
Приклад відповіді
Middleware — проміжний обробник, який виконується до контролера (і може обробити відповідь після). Приклади: auth перевіряє вхід, throttle обмежує частоту запитів, verified вимагає підтвердженого email.
Middleware можна застосувати глобально, до групи маршрутів або до окремого маршруту. Власний створюють командою php artisan make:middleware.
JuniorLaravel
Що таке Service Container і як він пов'язаний із Dependency Injection?
Приклад відповіді
Service Container — механізм Laravel, який створює об'єкти й автоматично підставляє їхні залежності. Якщо контролер у конструкторі просить OrderService, контейнер створить його разом із залежностями самого сервісу.
Для інтерфейсів у провайдері вказують реалізацію: $this->app->bind(PaymentGateway::class, LiqPayGateway::class). Це і є Dependency Injection: клас отримує залежності, а не створює їх сам, тому в тестах їх легко підмінити.
JuniorLaravel
Що таке Service Provider? Для чого потрібні методи register() і boot()?
Приклад відповіді
Service Provider — місце, де застосунок налаштовує свої сервіси під час запуску.
register() — лише реєстрація в контейнері (bind, singleton); тут не можна звертатися до інших сервісів, бо вони можуть бути ще не зареєстровані;
boot() — викликається після реєстрації всіх провайдерів: тут налаштовують події, макроси, правила валідації, обмеження частоти запитів.
Свої провайдери реєструють у bootstrap/providers.php.
JuniorLaravel
Як працює Eloquent ORM?
Приклад відповіді
Eloquent реалізує патерн Active Record: кожна таблиця має модель, а кожен рядок — об'єкт моделі. Модель Order за замовчуванням працює з таблицею orders.
Eloquent підтримує зв'язки, приведення типів (casts), аксесори й мутатори, області запитів (scopes), події моделей і м'яке видалення.
JuniorLaravel
Як реалізувати зв'язки hasOne, hasMany, belongsTo та belongsToMany?
Приклад відповіді
class User extends Model {
public function profile() { return $this->hasOne(Profile::class); }
public function orders() { return $this->hasMany(Order::class); }
public function roles() { return $this->belongsToMany(Role::class); }
}
class Order extends Model {
public function user() { return $this->belongsTo(User::class); }
}
hasOne/hasMany — зовнішній ключ у пов'язаній таблиці (orders.user_id), belongsTo — у поточній. belongsToMany використовує проміжну таблицю role_user.
JuniorLaravel
Що таке поліморфні зв'язки Eloquent? Наведіть приклад.
Приклад відповіді
Поліморфний зв'язок дає одній моделі належати різним моделям через одну таблицю. Наприклад, коментарі можна залишати і до статей, і до відео:
// comments: id, body, commentable_id, commentable_type
class Comment extends Model {
public function commentable() { return $this->morphTo(); }
}
class Post extends Model {
public function comments() { return $this->morphMany(Comment::class, 'commentable'); }
}
Через Relation::enforceMorphMap() у типі зберігають короткі назви (post) замість імен класів.
JuniorLaravel
Що таке масове призначення атрибутів (mass assignment)? Як працюють $fillable і $guarded?
Приклад відповіді
Масове призначення — заповнення моделі масивом: User::create($request->all()). Небезпека: зловмисник додасть у форму поле is_admin=1, і воно збережеться.
$fillable — білий список полів, які можна заповнювати масово, $guarded — чорний список. Безпечніше використовувати $fillable і передавати лише перевірені дані: User::create($request->validated()).
JuniorLaravel
Що таке міграції, сіди та фабрики? Для чого вони потрібні?
Приклад відповіді
Міграції описують зміни структури БД;
фабрики генерують моделі з тестовими даними (User::factory()->count(10)->create()), використовуючи Faker;
сіди наповнюють базу початковими або демо-даними (php artisan db:seed).
Разом вони дають змогу будь-кому розгорнути проєкт з робочою базою однією командою php artisan migrate --seed, а фабрики — основа тестів.
JuniorLaravel
Чим відрізняються find(), first(), get() і paginate()?
Приклад відповіді
find($id) — запис за первинним ключем або null; findOrFail кине 404;
first() — перший запис за умовами запиту або null;
get() — колекція всіх записів за умовами;
paginate(20) — сторінка записів плюс інформація про пагінацію для посилань.
Для великих таблиць get() без обмежень небезпечний — він завантажить усе в пам'ять.
JuniorLaravel
Що таке N+1 проблема в Eloquent? Як її вирішити за допомогою with()?
Приклад відповіді
N+1 — коли для кожного з N записів окремим запитом завантажується зв'язок: 1 запит на замовлення + 50 запитів на клієнтів.
// погано: запит у кожній ітерації
foreach (Order::all() as $order) echo $order->customer->name;
// добре: 2 запити
foreach (Order::with('customer')->get() as $order) echo $order->customer->name;
У режимі розробки варто ввімкнути Model::preventLazyLoading(), щоб такі місця кидали виняток.
JuniorLaravel
Чим відрізняються has() і whereHas()?
Приклад відповіді
Обидва фільтрують моделі за наявністю зв'язку. has('orders') — користувачі, у яких є хоча б одне замовлення, можна вказати кількість: has('orders', '>=', 3).
whereHas('orders', fn ($q) => $q->where('status', 'paid')) — додає умови до зв'язку: користувачі з оплаченими замовленнями. Протилежні — doesntHave і whereDoesntHave. Важливо: вони лише фільтрують, а не завантажують зв'язок — для цього потрібен with.
JuniorLaravel
Що таке Query Builder? Коли використовують його замість Eloquent?
Приклад відповіді
Query Builder (DB::table('orders')) будує SQL-запити через ланцюжок методів і повертає прості об'єкти, а не моделі.
Його обирають для звітів і агрегатів, масових оновлень, складних запитів, де моделі не потрібні, і коли важлива швидкодія на великих обсягах. Eloquent зручніший для звичайної роботи із сутностями, зв'язками й подіями моделей.
JuniorLaravel
Як працює валідація даних у Laravel?
Приклад відповіді
Найпростіше — $request->validate([...]) у контролері, але краще окремий Form Request:
class StoreOrderRequest extends FormRequest {
public function rules(): array {
return [
'email' => ['required', 'email'],
'quantity' => ['required', 'integer', 'min:1'],
];
}
}
Якщо дані некоректні, Laravel поверне користувача з помилками (або JSON зі статусом 422 для API). Далі використовують лише $request->validated().
JuniorLaravel
Як створити власне правило валідації?
Приклад відповіді
Командою php artisan make:rule UkrainianPhone створюється клас із методом validate:
class UkrainianPhone implements ValidationRule {
public function validate(string $attribute, mixed $value, Closure $fail): void {
if (!preg_match('/^\+380\d{9}$/', $value)) {
$fail('Вкажіть номер у форматі +380XXXXXXXXX.');
}
}
}
Використання: 'phone' => ['required', new UkrainianPhone]. Для разових перевірок підходить і замикання в масиві правил.
JuniorLaravel
Як працюють автентифікація та авторизація в Laravel?
Приклад відповіді
Автентифікацію забезпечують guards (сесія для вебу, токени для API) і готові стартові набори (Breeze, Jetstream, Fortify); для API та SPA — Sanctum. Поточний користувач — auth()->user(), захист маршрутів — middleware auth.
Авторизація — через Gates (прості перевірки) і Policies (правила для моделі): $this->authorize('update', $post) або @can('update', $post) у Blade.
JuniorLaravel
Що таке Gates і Policies?
Приклад відповіді
Gate — замикання, що перевіряє дію, не прив'язану до моделі: Gate::define('view-reports', fn (User $u) => $u->is_manager).
Policy — клас із правилами для конкретної моделі: PostPolicy з методами view, update, delete. Laravel автоматично знаходить політику за назвою моделі. Політики зручніші, коли правил багато, а Gates — для одиничних перевірок.
JuniorLaravel
Як захистити форму від CSRF?
Приклад відповіді
Додати директиву @csrf у форму Blade — вона вставить приховане поле з токеном. Middleware перевіряє токен для всіх POST, PUT, PATCH і DELETE запитів у web-маршрутах і повертає помилку 419, якщо токен відсутній або застарів.
Для AJAX-запитів токен передають у заголовку X-CSRF-TOKEN (його можна взяти з мета-тегу). Виключення з перевірки (наприклад, вебхуки платіжних систем) налаштовують окремо і захищають підписом запиту.
JuniorLaravel
Як працюють черги (Queues) та фонові завдання (Jobs)?
Приклад відповіді
Job — клас із методом handle(), який виконується у фоні. Його відправляють у чергу: SendInvoice::dispatch($order). Воркер (php artisan queue:work) забирає задачі з черги (Redis, БД, SQS) і виконує.
Так повільні операції (листи, PDF, звернення до API) не затримують відповідь користувачу. На продакшні воркери запускають через Supervisor або Horizon і перезапускають після деплою командою queue:restart.
JuniorLaravel
Що таке Events і Listeners? Коли їх використовують?
Приклад відповіді
Подія повідомляє, що щось сталося (OrderPaid), а слухачі реагують на неї: надіслати лист, нарахувати бонуси, оновити статистику. Один код генерує подію, і йому не потрібно знати про всі реакції.
Це зменшує зв'язність: додати нову реакцію можна новим слухачем без зміни коду оплати. Слухачі можна виконувати в черзі (ShouldQueue). Але надмірна кількість подій ускладнює розуміння, що саме відбувається.
JuniorLaravel
Як реалізувати кешування в Laravel?
Приклад відповіді
Через фасад Cache з драйвером Redis, Memcached, файлами чи БД:
$categories = Cache::remember('categories', now()->addHour(), function () {
return Category::orderBy('name')->get();
});
При зміні даних кеш очищають: Cache::forget('categories'), наприклад у події моделі. Також є кешування конфігурації й маршрутів для продакшну (php artisan optimize) і атомарні блокування Cache::lock().
JuniorLaravel
Як працюють файлові сховища Laravel та фасад Storage?
Приклад відповіді
Laravel абстрагує роботу з файлами через «диски»: локальний, public, S3 і сумісні сховища. Код однаковий незалежно від місця зберігання:
Для публічних локальних файлів виконують php artisan storage:link. Для приватних файлів видають тимчасові посилання (temporaryUrl), а не відкривають папку всім.
JuniorLaravel
Як обробляти винятки та налаштовувати логування?
Приклад відповіді
Обробку винятків налаштовують у bootstrap/app.php (withExceptions): можна звітувати про певні винятки в Sentry, перетворювати їх на потрібні відповіді чи ігнорувати. Для бізнес-помилок створюють власні класи винятків з методами report() і render().
Логування — через Log::info(), Log::error() з контекстом: Log::error('Оплата не пройшла', ['order_id' => $id]). Канали налаштовують у config/logging.php: щоденні файли, stderr для Docker, Slack для критичних помилок.
JuniorLaravel
Що таке API Resources? Для чого вони потрібні?
Приклад відповіді
API Resource перетворює модель на JSON-відповідь у контрольованому форматі:
class UserResource extends JsonResource {
public function toArray($request): array {
return ['id' => $this->id, 'name' => $this->name, 'orders' => OrderResource::collection($this->whenLoaded('orders'))];
}
}
Переваги: структура API не залежить від колонок БД, не «витікають» зайві поля (пароль, службові дані), зв'язки додаються лише якщо завантажені.
JuniorLaravel
Як писати автоматизовані тести в Laravel? Чим відрізняються unit-тести від feature-тестів?
Приклад відповіді
Laravel підтримує PHPUnit і Pest. Unit-тест перевіряє окремий клас чи функцію ізольовано, без БД і HTTP. Feature-тест перевіряє поведінку застосунку через HTTP-запит, з базою даних:
public function test_guest_cannot_create_order(): void {
$this->postJson('/api/orders', [])->assertUnauthorized();
}
Для чистої БД між тестами використовують RefreshDatabase, для зовнішніх сервісів — фейки: Mail::fake(), Queue::fake(), Http::fake().
JuniorLaravel
Як запускати Artisan-команди? Як створити власну команду?
Приклад відповіді
Команди запускають через php artisan назва: migrate, route:list, tinker, make:model. Власна — php artisan make:command ImportProducts:
class ImportProducts extends Command {
protected $signature = 'products:import {file} {--dry-run}';
public function handle(): int {
$this->info('Імпорт...');
return self::SUCCESS;
}
}
Команди використовують для імпорту, обслуговування й задач за розкладом.
JuniorLaravel
Що таке Laravel Scheduler і як він працює разом із cron?
Приклад відповіді
Scheduler дає описати всі періодичні задачі в коді (routes/console.php), а не в crontab сервера:
На сервері потрібен лише один запис cron, що щохвилини викликає php artisan schedule:run. Опція onOneServer() не дає задачі виконатися одночасно на кількох серверах.
JuniorLaravel
Як працюють конфігурація та .env? Чому не варто звертатися до env() безпосередньо з коду застосунку?
Приклад відповіді
.env містить налаштування конкретного середовища (паролі БД, ключі API) і не потрапляє в Git. Файли в config/ читають ці значення: 'key' => env('LIQPAY_KEY'), а код застосунку використовує config('services.liqpay.key').
На продакшні виконують php artisan config:cache: після цього .env не читається, і env() поза файлами конфігурації поверне null. Тому env() викликають лише в config/.
JuniorLaravel
Як запобігти проблемам із продуктивністю під час роботи з великими колекціями записів?
Приклад відповіді
Не завантажувати все через get(): використовувати chunk(), chunkById(), lazy() або cursor();
вибирати лише потрібні стовпці (select);
жадібне завантаження зв'язків через with;
масові операції однією командою: update(), upsert(), insert();
рахувати на боці БД (count, sum, withCount), а не через колекції;
довгу обробку виносити в черги.
JuniorLaravel
Як організувати повторні спроби виконання завдань і обробку невдалих jobs?
Приклад відповіді
У класі job задають $tries (кількість спроб), $backoff (затримки між ними, наприклад [10, 60, 300]) і $timeout. Метод failed(Throwable $e) викликається, коли всі спроби вичерпано, — там можна сповістити команду.
Невдалі задачі потрапляють у таблицю failed_jobs: їх переглядають і повторюють командою php artisan queue:retry. Job має бути ідемпотентним, щоб повторний запуск не, наприклад, двічі списав кошти.
JuniorComposer, Git та інструменти
Що таке Composer і для чого він потрібен?
Приклад відповіді
Composer — менеджер залежностей PHP. Він встановлює бібліотеки з Packagist потрібних версій разом із їхніми залежностями, генерує автозавантажувач класів і запускає скрипти проєкту.
Чим відрізняються require та require-dev у composer.json?
Приклад відповіді
require — залежності, потрібні для роботи застосунку (фреймворк, SDK платіжної системи). require-dev — лише для розробки: PHPUnit, PHPStan, Laravel Pint, Debugbar.
На продакшні виконують composer install --no-dev --optimize-autoloader, щоб не встановлювати інструменти розробки й пришвидшити автозавантаження.
JuniorComposer, Git та інструменти
Для чого потрібні composer.json і composer.lock?
Приклад відповіді
composer.json описує, які пакети потрібні й у яких діапазонах версій (^11.0). composer.lock фіксує точні встановлені версії всіх пакетів, включно із вкладеними залежностями.
Обидва файли комітять у Git: завдяки lock-файлу в усіх розробників і на сервері встановлюються однакові версії.
JuniorComposer, Git та інструменти
Чим відрізняються composer install і composer update?
Приклад відповіді
composer install встановлює точні версії з composer.lock — використовується при розгортанні проєкту й на сервері. composer update шукає новіші версії в межах обмежень composer.json, встановлює їх і переписує lock-файл.
update виконують свідомо, перевіряють зміни й тести, а не на продакшні. Оновити один пакет: composer update vendor/package.
JuniorComposer, Git та інструменти
Що таке PSR? Які стандарти PSR ви знаєте?
Приклад відповіді
PSR — рекомендації PHP-FIG, які роблять бібліотеки сумісними між собою:
PSR-1 і PSR-12 (зараз PER Coding Style) — стиль коду;
PSR-4 — автозавантаження класів;
PSR-3 — інтерфейс логера;
PSR-7 — HTTP-повідомлення, PSR-15 — обробники й middleware;
PSR-11 — контейнер залежностей;
PSR-6 і PSR-16 — кешування;
PSR-18 — HTTP-клієнт.
JuniorComposer, Git та інструменти
Якими командами Git можна перевірити стан файлів, додати зміни та створити коміт?
Приклад відповіді
git status # які файли змінено
git diff # що саме змінено
git add src/Order.php # додати файл до коміту (git add -p — частинами)
git commit -m 'Додати перевірку залишку на складі'
git log --oneline # історія комітів
Хороше повідомлення коміту коротко пояснює, що і навіщо змінено.
JuniorComposer, Git та інструменти
Чим відрізняються git pull і git fetch?
Приклад відповіді
git fetch завантажує нові коміти з віддаленого репозиторію, але не змінює вашу робочу гілку — можна спершу подивитися зміни. git pull — це fetch плюс злиття (або rebase) у поточну гілку.
Багато розробників налаштовують git pull --rebase, щоб уникати зайвих merge-комітів.
JuniorComposer, Git та інструменти
Що таке гілка (branch)? Навіщо створювати окремі гілки для завдань?
Приклад відповіді
Гілка — незалежна лінія розробки: git switch -c feature/order-export. В окремій гілці можна працювати над задачею, не ламаючи основний код.
Зміни потрапляють в основну гілку через pull request після код-рев'ю й проходження тестів у CI. Короткоживучі гілки на одну задачу легше переглядати й зливати без конфліктів.
JuniorComposer, Git та інструменти
Що таке merge та rebase?
Приклад відповіді
Обидва переносять зміни з однієї гілки в іншу. merge створює коміт злиття й зберігає історію такою, як вона була. rebase переписує ваші коміти поверх нової бази — історія стає лінійною.
Правило: не робити rebase гілок, які вже використовують інші, бо зміниться історія. Для своєї локальної гілки rebase на свіжий main перед pull request — звична практика.
JuniorComposer, Git та інструменти
Як розв'язати конфлікт злиття в Git?
Приклад відповіді
Git позначає конфліктні місця маркерами <<<<<<<, =======, >>>>>>>;
відкрити файли (IDE має зручний інструмент), вирішити, який код лишити, або поєднати обидва варіанти;
прибрати маркери, перевірити, що код працює і тести проходять;
git add для виправлених файлів і git commit (або git rebase --continue).
Якщо незрозуміло, чий код правильний, варто уточнити в автора змін.
JuniorComposer, Git та інструменти
Чим відрізняються git reset, git revert і git restore?
Приклад відповіді
git restore file — скасувати незакомічені зміни у файлі (або --staged — прибрати з індексу);
git reset — перемістити гілку на інший коміт; --hard видаляє зміни, тому для спільних гілок не підходить;
git revert <commit> — створює новий коміт, що скасовує зміни вказаного. Безпечний для спільних гілок, бо не переписує історію.
JuniorComposer, Git та інструменти
Що таке .gitignore? Які файли зазвичай не додають до репозиторію?
Приклад відповіді
.gitignore перелічує файли й папки, які Git не відстежує. Зазвичай це:
.env із секретами;
vendor/ і node_modules/ — встановлюються командами;
логи, кеш, завантажені файли (storage/);
зібрані фронтенд-файли;
налаштування IDE (.idea/, .vscode/).
Якщо файл уже закомічено, .gitignore не прибере його — потрібно git rm --cached.
JuniorComposer, Git та інструменти
Що таке Docker і чим контейнер відрізняється від віртуальної машини?
Приклад відповіді
Docker пакує застосунок разом з оточенням (PHP потрібної версії, розширення, Nginx) у контейнер, який однаково працює на будь-якій машині.
Віртуальна машина емулює цілий комп'ютер із власною ОС — вона важка й повільно запускається. Контейнер використовує ядро хост-системи й ізолює лише процеси, тому запускається за секунди й займає менше ресурсів.
JuniorComposer, Git та інструменти
Що таке Dockerfile і Docker Compose?
Приклад відповіді
Dockerfile — інструкція зі збирання образу: базовий образ, встановлення розширень PHP, копіювання коду, команда запуску.
Docker Compose описує кілька сервісів, що працюють разом (PHP, Nginx, MySQL, Redis), у файлі compose.yaml і запускає їх однією командою docker compose up. Для Laravel готове рішення — Laravel Sail.
JuniorComposer, Git та інструменти
Що таке SSH і для чого його використовують під час розробки?
Приклад відповіді
SSH — протокол захищеного підключення до віддаленого сервера: ssh user@server. Через нього виконують команди на сервері, переглядають логи, копіюють файли (scp, rsync).
Також SSH-ключі використовують для доступу до Git-репозиторіїв без пароля. Приватний ключ не можна нікому передавати, а вхід за паролем на серверах краще вимикати.
JuniorComposer, Git та інструменти
Що таке Linux-процеси та як переглянути журнали роботи застосунку?
Приклад відповіді
Процес — запущена програма з власним ідентифікатором (PID): PHP-FPM, Nginx, воркер черги. Переглянути: ps aux | grep php, top або htop; керувати сервісами — systemctl status nginx.
Логи: tail -f storage/logs/laravel.log, /var/log/nginx/error.log, journalctl -u php8.3-fpm, для контейнерів — docker logs -f container. Для пошуку — grep 'ERROR' laravel.log.
JuniorComposer, Git та інструменти
Яке середовище розробки ви використовуєте та чому?
Приклад відповіді
Тут немає правильної відповіді — роботодавець хоче побачити, що ви вмієте ефективно працювати з інструментами. Наприклад: PhpStorm з Laravel Idea для навігації, рефакторингу й налагодження, або VS Code з розширеннями (Intelephense, PHP Debug).
Варто згадати Xdebug для покрокового налагодження, Docker або Laravel Herd для локального оточення, лінтери й форматери (PHPStan, Pint), а також AI-асистента — і як ви перевіряєте його підказки.
JuniorПрактичні завдання
Напишіть функцію, яка перевіряє, чи є рядок паліндромом.
Важливо використовувати mb_-функції: звичайний strrev ламає кирилицю, бо працює з байтами. Варто уточнити в інтерв'юера, чи ігнорувати пробіли й регістр.
JuniorПрактичні завдання
Напишіть функцію, яка знаходить найбільше та найменше число в масиві.
Приклад відповіді
Простий варіант — вбудовані функції: [min($nums), max($nums)]. Якщо просять без них — один прохід:
function minMax(array $nums): array {
if ($nums === []) throw new InvalidArgumentException('Порожній масив');
$min = $max = $nums[0];
foreach ($nums as $n) {
if ($n < $min) $min = $n;
if ($n > $max) $max = $n;
}
return [$min, $max];
}
Складність O(n). Варто згадати обробку порожнього масиву.
JuniorПрактичні завдання
Порахуйте кількість входжень кожного елемента в масиві.
Ітеративний варіант працює за O(n). Наївна рекурсія fib(n-1) + fib(n-2) — експоненційна, і на співбесіді варто це зазначити. Можна також показати варіант із генератором.
JuniorПрактичні завдання
Реалізуйте рекурсивний підрахунок суми чисел від 1 до N.
Приклад відповіді
function sumTo(int $n): int {
if ($n <= 0) return 0; // базовий випадок
return $n + sumTo($n - 1);
}
sumTo(5); // 15
Варто згадати, що на практиці краще формула $n * ($n + 1) / 2 — O(1), а глибока рекурсія при великому N може вичерпати стек.
JuniorПрактичні завдання
Напишіть функцію, яка перевіряє, чи містить рядок лише цифри.
Приклад відповіді
function onlyDigits(string $s): bool {
return ctype_digit($s);
}
// або регулярним виразом
preg_match('/^\d+$/', $s) === 1;
Пастка: is_numeric('1e5') і is_numeric('-3.5') повертають true, тому для перевірки «лише цифри» вони не підходять. ctype_digit() приймає лише рядки: передача цілого числа застаріла з PHP 8.1, тож значення з форм перевіряють як рядки.
JuniorПрактичні завдання
Реалізуйте простий клас User із приватними властивостями, конструктором і гетерами.
Приклад відповіді
final class User {
public function __construct(
private readonly int $id,
private string $email,
) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Некоректний email');
}
}
public function getId(): int { return $this->id; }
public function getEmail(): string { return $this->email; }
}
Варто показати сучасний синтаксис (constructor promotion, readonly) і перевірку даних у конструкторі, щоб об'єкт не міг існувати в некоректному стані.
JuniorПрактичні завдання
Створіть інтерфейс PaymentGateway і дві його реалізації.
Приклад відповіді
interface PaymentGateway {
public function charge(int $amountCents, string $orderId): string; // повертає ID транзакції
}
final class LiqPayGateway implements PaymentGateway {
public function charge(int $amountCents, string $orderId): string { /* виклик API LiqPay */ return 'lp_123'; }
}
final class FakeGateway implements PaymentGateway {
public array $charges = [];
public function charge(int $amountCents, string $orderId): string {
$this->charges[] = [$amountCents, $orderId];
return 'fake_' . count($this->charges);
}
}
Фейкова реалізація корисна для тестів. Суми зберігаємо в копійках, щоб уникнути помилок округлення.
JuniorПрактичні завдання
Реалізуйте простий приклад Dependency Injection.
Приклад відповіді
final class CheckoutService {
public function __construct(private PaymentGateway $gateway) {}
public function pay(Order $order): string {
return $this->gateway->charge($order->totalCents, $order->id);
}
}
// у робочому коді
$service = new CheckoutService(new LiqPayGateway());
// у тесті
$service = new CheckoutService(new FakeGateway());
Сервіс не знає, яка платіжна система використовується. У Laravel реалізацію для інтерфейсу вказують у сервіс-провайдері, і контейнер передасть її автоматично.
JuniorПрактичні завдання
Що виведе код $a = 5; $b = $a++; $c = ++$a; echo "$a $b $c";? Поясніть результат.
Приклад відповіді
Виведе 7 5 7.
$b = $a++ — спочатку $b отримує поточне значення 5, потім $a стає 6;
$c = ++$a — спочатку $a збільшується до 7, потім $c отримує 7.
JuniorПрактичні завдання
Що виведе код $x = "10"; $y = 10; var_dump($x == $y); var_dump($x === $y); і чому?
Приклад відповіді
bool(true) і bool(false).
== порівнює з приведенням типів: числовий рядок "10" перетворюється на число 10, і значення рівні. === порівнює ще й типи: string не дорівнює int.
JuniorПрактичні завдання
Спроєктуйте таблиці для зберігання авторів і книг. Напишіть запит, який повертає кожного автора та кількість його книг, включно з авторами без книг.
Приклад відповіді
Якщо в книги може бути кілька авторів, потрібна проміжна таблиця:
CREATE TABLE authors (id BIGINT PRIMARY KEY, name VARCHAR(255) NOT NULL);
CREATE TABLE books (id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL);
CREATE TABLE author_book (
author_id BIGINT REFERENCES authors(id),
book_id BIGINT REFERENCES books(id),
PRIMARY KEY (author_id, book_id)
);
SELECT a.id, a.name, COUNT(ab.book_id) AS books_count
FROM authors a
LEFT JOIN author_book ab ON ab.author_id = a.id
GROUP BY a.id, a.name;
LEFT JOIN лишає авторів без книг, а COUNT(ab.book_id) дасть для них 0 (на відміну від COUNT(*), який порахував би 1).
JuniorПрактичні завдання
Напишіть SQL-запит, який знаходить другий за величиною унікальний оклад працівника.
Приклад відповіді
SELECT DISTINCT salary
FROM employees
ORDER BY salary DESC
LIMIT 1 OFFSET 1;
-- або без LIMIT
SELECT MAX(salary) FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);
DISTINCT важливий: якщо два працівники мають однаковий найбільший оклад, без нього повернеться той самий максимум. Варіант із MAX поверне NULL, якщо другого окладу немає. Для N-го значення зручні віконні функції DENSE_RANK().
JuniorПрактичні завдання
Знайдіть усіх клієнтів, які не мають жодного замовлення.
Приклад відповіді
SELECT c.*
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;
-- або
SELECT * FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
Варіант NOT IN (SELECT customer_id FROM orders) небезпечний: якщо в підзапиті трапиться NULL, результат буде порожнім. У Laravel — Customer::doesntHave('orders')->get().
JuniorПрактичні завдання
Напишіть запит для визначення трьох найпопулярніших товарів за кількістю продажів.
Приклад відповіді
SELECT p.id, p.name, SUM(oi.quantity) AS sold
FROM order_items oi
JOIN products p ON p.id = oi.product_id
JOIN orders o ON o.id = oi.order_id
WHERE o.status = 'paid'
GROUP BY p.id, p.name
ORDER BY sold DESC
LIMIT 3;
Варто уточнити, що означає «популярність»: кількість одиниць (SUM(quantity)) чи кількість замовлень (COUNT(DISTINCT order_id)), і враховувати лише оплачені замовлення.
JuniorПрактичні завдання
Є таблиця з мільйонами записів, і запит виконується повільно. Які ваші дії для пошуку та усунення проблеми?
Приклад відповіді
Відтворити запит і виміряти час на даних продакшн-обсягу;
подивитися EXPLAIN: чи є повне сканування, скільки рядків переглядається, чи потрібне сортування на диску;
додати індекс під умови WHERE, JOIN і ORDER BY (складений, з правильним порядком стовпців);
вибирати лише потрібні стовпці, додати LIMIT, замінити OFFSET на keyset-пагінацію;
перевірити, чи не обгорнуте поле функцією (WHERE DATE(created_at) = ... не використає індекс);
для важких звітів — кеш, агрегатні таблиці або репліка для читання.
Після змін — повторно виміряти й порівняти.
JuniorПрактичні завдання
Напишіть транзакцію, яка створює замовлення та зменшує кількість товару на складі.
with завантажить усі категорії одним додатковим запитом. Синтаксис category:id,name обмежує стовпці, але category_id у вибірці товарів обов'язковий, інакше зв'язок не знайдеться.
JuniorПрактичні завдання
Реалізуйте зв'язок «багато до багатьох» між користувачами та ролями.
Приклад відповіді
// міграція
Schema::create('role_user', function (Blueprint $t) {
$t->foreignId('user_id')->constrained()->cascadeOnDelete();
$t->foreignId('role_id')->constrained()->cascadeOnDelete();
$t->primary(['user_id', 'role_id']);
});
class User extends Model {
public function roles() { return $this->belongsToMany(Role::class)->withTimestamps(); }
}
$user->roles()->attach($roleId);
$user->roles()->sync([1, 3]); // лишити тільки ці ролі
$user->roles()->detach($roleId);
Для таймстемпів у проміжній таблиці додають $t->timestamps().
JuniorПрактичні завдання
Створіть Job для надсилання електронного листа у фоновому режимі.
Приклад відповіді
class SendWelcomeEmail implements ShouldQueue {
use Queueable;
public int $tries = 3;
public array $backoff = [30, 120];
public function __construct(public User $user) {}
public function handle(): void {
Mail::to($this->user)->send(new WelcomeMail($this->user));
}
}
SendWelcomeEmail::dispatch($user)->afterCommit();
afterCommit гарантує, що задача піде в чергу лише після збереження користувача в БД. Модель серіалізується за ID і завантажується заново у воркері.
JuniorПрактичні завдання
Напишіть feature-тест для endpoint, який повертає список товарів.
Приклад відповіді
class ProductIndexTest extends TestCase {
use RefreshDatabase;
public function test_it_returns_paginated_products(): void {
Product::factory()->count(3)->create();
$this->getJson('/api/products')
->assertOk()
->assertJsonCount(3, 'data')
->assertJsonStructure(['data' => [['id', 'name', 'price']], 'meta']);
}
}
Добре додати тести на порожній список, фільтри й на те, що прихованих полів у відповіді немає.
JuniorПрактичні завдання
Як реалізувати пагінацію списку з 100 000 товарів?
Приклад відповіді
Звичайний paginate() використовує OFFSET і рахує загальну кількість через COUNT(*) — на далеких сторінках і великих таблицях це повільно.
simplePaginate() — без підрахунку загальної кількості (лише «вперед/назад»);
cursorPaginate() — keyset-пагінація за індексованим полем (WHERE id > ?), стабільно швидка на будь-якій сторінці;
індекс під сортування, вибірка лише потрібних стовпців, кешування кількості.
Для нескінченної прокрутки та API найкраще підходить курсорна пагінація.
JuniorПрактичні завдання
Як організувати завантаження файлу з перевіркою типу та розміру?
Правило mimes перевіряє реальний вміст файлу, а не лише розширення. Ім'я файлу генерується автоматично — не варто зберігати під назвою від користувача. Приватні документи зберігають поза публічною папкою й видають через тимчасові посилання. Також варто обмежити розмір у налаштуваннях PHP і Nginx.
JuniorПрактичні завдання
Що робити, якщо після розгортання Laravel-застосунок повертає помилку 500?
Приклад відповіді
Подивитися storage/logs/laravel.log і логи Nginx / PHP-FPM;
перевірити .env на сервері: чи є APP_KEY, доступи до БД, чи не забули нові змінні;
права на запис для storage і bootstrap/cache;
чи виконано composer install --no-dev, міграції, php artisan optimize:clear і повторно optimize;
версію PHP і розширення на сервері;
чи перезапущені PHP-FPM і воркери черг.
Якщо причина незрозуміла, а помилка критична — відкотити реліз і розбиратися спокійно.
JuniorРобочі ситуації
Ви випадково внесли секретний ключ до коміту. Що робитимете?
Приклад відповіді
Головне — вважати ключ скомпрометованим, навіть якщо коміт ще не запушено:
одразу відкликати й перевипустити ключ у сервісі;
повідомити тімліда або відповідального за безпеку;
перенести секрет у .env і додати файл у .gitignore;
якщо коміт не запушено — виправити історію (git commit --amend або interactive rebase); якщо запушено — очистити історію (git filter-repo) лише за домовленістю з командою;
перевірити логи сервісу на підозріле використання.
Просто видалити ключ наступним комітом недостатньо — він лишається в історії.
JuniorРобочі ситуації
Після злиття гілок перестав працювати endpoint. Як знайти причину?
Приклад відповіді
Відтворити помилку і подивитися лог та stack trace;
переглянути diff злиття, особливо місця, де були конфлікти, — часто зміни вирішено неправильно;
запустити тести; якщо тест для endpoint падає — він підкаже місце;
якщо причина неочевидна — git bisect, щоб знайти коміт, після якого все зламалося;
перевірити міграції, конфігурацію й залежності, які змінила інша гілка.
Після виправлення — додати тест, який зловив би цю проблему.
JuniorРобочі ситуації
Ви отримали завдання, але вимоги неповні. Як діятимете?
Приклад відповіді
Не вигадувати вимоги самостійно, а уточнити: сформулювати конкретні питання до менеджера чи замовника, запропонувати варіанти рішення з наслідками кожного й зафіксувати домовленості письмово в задачі.
Якщо відповіді доведеться чекати — почати з частини, яка зрозуміла, і заздалегідь назвати припущення. Роботодавець хоче побачити, що ви не мовчите тиждень і не робите «як здалося».
JuniorРобочі ситуації
Ваш код працює локально, але не працює на сервері. Які перевірки виконаєте?
Приклад відповіді
Логи застосунку й сервера: точний текст помилки;
відмінності оточення: версія PHP та розширення, змінні .env, кешована конфігурація;
чи виконано міграції й composer install на сервері;
права доступу до файлів, регістр у назвах файлів (Linux чутливий до регістру, macOS і Windows — ні);
мережеві доступи до БД, Redis і зовнішніх API, налаштування firewall;
чи запущені воркери черг і cron для Scheduler.
Docker допомагає зменшити різницю між локальним і серверним оточенням.
JuniorРобочі ситуації
Потрібно додати нову функцію в застосунок, але наявний код складно тестувати. З чого почнете?
Приклад відповіді
Розібратися, як працює наявний код, і зафіксувати поточну поведінку тестами високого рівня (feature-тести через HTTP);
виділити залежності (зовнішні API, час, БД) у класи, які можна підмінити;
невеликими кроками винести логіку з контролера в сервіс, запускаючи тести після кожного кроку;
нову функцію писати вже в тестованому вигляді.
Великий рефакторинг без узгодження з командою не варто починати — краще домовитися про обсяг.
JuniorПрактичні завдання
Що таке складність алгоритму O(1), O(log n), O(n) та O(n²)?
Приклад відповіді
Нотація «O велике» показує, як зростає час роботи зі збільшенням обсягу даних:
O(1) — сталий час: доступ до елемента масиву за ключем;
O(log n) — бінарний пошук, пошук в індексі БД;
O(n) — один прохід по масиву;
O(n²) — вкладені цикли по тих самих даних, наприклад in_array усередині foreach.
Для 100 000 елементів різниця між O(n) і O(n²) — це мілісекунди проти хвилин.
JuniorPHP 8.x і ООП
Що таке SOLID на практиці? Покажіть приклад порушення одного з принципів.
Приклад відповіді
Порушення Single Responsibility — «товстий» метод контролера:
public function store(Request $r) {
// валідація, розрахунок знижки, збереження, оплата, лист, лог — усе тут
}
Його важко тестувати й змінювати: зміна тексту листа зачіпає код оплати. Виправлення — Form Request для валідації, DiscountCalculator, CheckoutService, подія OrderPlaced зі слухачем для листа.
Порушення Open/Closed — switch ($type) для кожного способу доставки: новий спосіб вимагає змінювати наявний код замість додавання нового класу.
JuniorАрхітектура й безпека
Що таке ідемпотентність HTTP-запиту? Чому вона важлива для API?
Приклад відповіді
Ідемпотентний запит при повторному виконанні дає той самий результат, що й при першому. GET, PUT, DELETE ідемпотентні, POST — ні.
Це важливо, бо мережа ненадійна: клієнт може не отримати відповідь і повторити запит. Для платежів і створення замовлень використовують ключ ідемпотентності: клієнт надсилає унікальний Idempotency-Key, а сервер, отримавши той самий ключ удруге, повертає збережений результат замість повторної операції.
JuniorАрхітектура й безпека
Як не допустити повторного створення замовлення через подвійне натискання кнопки?
Приклад відповіді
Потрібен захист на кількох рівнях:
у браузері — блокувати кнопку після першого натискання;
на сервері — ключ ідемпотентності або унікальний токен форми, збережений разом із замовленням;
атомарне блокування Cache::lock('checkout:'.$userId, 10) на час обробки;
унікальний індекс у БД як останній рубіж.
Лише фронтенд-захисту недостатньо: запит можна повторити з мережевої вкладки або через повільну мережу.
JuniorАрхітектура й безпека
Чим відрізняються кешування в пам'яті, Redis і кешування на рівні браузера?
Приклад відповіді
Кеш у пам'яті процесу (статична змінна, once() у Laravel) живе лише в межах одного запиту чи процесу — найшвидший, але не спільний;
Redis — окремий сервіс, спільний для всіх серверів і воркерів, переживає запити; підходить для даних застосунку, сесій, черг, блокувань;
кеш браузера й CDN керується HTTP-заголовками (Cache-Control, ETag) і зберігає статику та відповіді на боці клієнта — запит до сервера взагалі не надходить.
JuniorАрхітектура й безпека
Що таке race condition? Наведіть приклад із двома одночасними запитами.
Приклад відповіді
Race condition — помилка, коли результат залежить від того, в якому порядку виконаються паралельні операції.
Приклад: на складі лишився 1 товар. Два запити одночасно читають stock = 1, обидва перевіряють «достатньо», обидва зменшують — продано 2 товари, залишок -1.
Рішення: атомарний UPDATE ... SET stock = stock - 1 WHERE stock > 0 і перевірка кількості змінених рядків, або lockForUpdate() у транзакції, або Cache::lock().
JuniorАрхітектура й безпека
Для чого потрібні черги, якщо завдання можна виконати безпосередньо в HTTP-запиті?
Приклад відповіді
Швидкість відповіді: користувач не чекає, поки надішлеться лист чи згенерується PDF;
надійність: якщо зовнішній сервіс недоступний, задача повториться пізніше, а не покаже користувачу помилку;
контроль навантаження: важкі задачі виконуються рівномірно воркерами, а не всі одночасно;
таймаути: HTTP-запит обмежений у часі, а фонова задача може працювати довше.
Але черга додає складності: потрібні воркери, моніторинг і ідемпотентні задачі.
JuniorАрхітектура й безпека
Як зберігати паролі користувачів? Чому не можна використовувати звичайний MD5?
Приклад відповіді
Паролі зберігають лише як хеш, отриманий повільною адаптивною функцією: password_hash($password, PASSWORD_DEFAULT) (bcrypt) або Argon2id; у Laravel — Hash::make(). Перевірка — password_verify().
MD5 і SHA-1 дуже швидкі: сучасна відеокарта перебирає мільярди варіантів за секунду, а для популярних паролів існують готові таблиці. Bcrypt і Argon2 навмисно повільні й автоматично додають сіль.
JuniorАрхітектура й безпека
Чому не варто зберігати API-ключі та паролі в Git?
Приклад відповіді
Історія Git зберігає все назавжди: навіть видалений ключ лишається в старих комітах. Репозиторій копіюють на ноутбуки розробників, у CI, сторонні сервіси; приватний репозиторій може стати публічним або витекти.
Боти постійно сканують GitHub на ключі хмарних сервісів і використовують їх за лічені хвилини. Секрети зберігають у .env поза Git і в менеджерах секретів, а в репозиторії лишають лише .env.example.
JuniorПроцеси й AI
Що таке code review і які проблеми ви шукаєте під час перевірки коду?
Приклад відповіді
Код-рев'ю — перевірка змін колегою перед злиттям. Мета — знайти помилки, поширити знання про код і підтримувати спільні стандарти.
На що дивляться: чи виконує код задачу, граничні випадки й обробку помилок, безпеку (валідація, SQL-ін'єкції, права доступу), N+1 і продуктивність, зрозумілість назв, наявність тестів. Коментарі пишуть конкретно й доброзичливо, з поясненням чому, а не «переписати».
JuniorПроцеси й AI
Чим відрізняються unit-, integration- та feature-тести?
Приклад відповіді
Unit-тест перевіряє один клас чи функцію ізольовано, залежності підмінено — швидкий;
інтеграційний тест перевіряє взаємодію кількох частин із реальною інфраструктурою: репозиторій із справжньою БД, клієнт зовнішнього API проти тестового сервера;
feature-тест (у Laravel) перевіряє сценарій через HTTP-запит: маршрут, middleware, валідацію, БД і відповідь.
Поширений підхід — багато швидких unit-тестів і основні сценарії покриті feature-тестами.
JuniorАрхітектура й безпека
Як би ви пояснили різницю між монолітом і мікросервісною архітектурою?
Приклад відповіді
Моноліт — один застосунок з однією кодовою базою, який розгортається цілком. Його простіше розробляти, тестувати й розгортати, тому для більшості проєктів це правильний старт.
Мікросервіси — кілька незалежних застосунків, кожен зі своєю відповідальністю й даними, які спілкуються через API чи черги. Вони дають незалежні релізи й масштабування окремих частин, але додають складність: мережеві збої, розподілені дані, моніторинг. Їх обирають, коли розмір команди й навантаження справді цього вимагають.
JuniorПроцеси й AI
Що таке технічний борг і як із ним працювати?
Приклад відповіді
Технічний борг — наслідки швидких або застарілих рішень, які сповільнюють розробку: дублювання коду, відсутність тестів, застарілі версії бібліотек, «тимчасові» милиці.
Його не можна повністю уникнути — інколи свідомий борг заради швидкого запуску виправданий. Важливо фіксувати його в задачах, пояснювати бізнесу вплив («кожна зміна в оплаті займає вдвічі більше часу»), виділяти час на виправлення й залишати код трохи кращим після кожної задачі.
JuniorПроцеси й AI
Як ви перевіряєте, що зміни не зламали наявний функціонал?
Приклад відповіді
Автоматичні тести локально й у CI перед злиттям;
статичний аналіз (PHPStan) і форматування (Pint);
ручна перевірка сценаріїв, яких торкнулися зміни, включно з граничними випадками;
перегляд diff перед комітом і код-рев'ю колегою;
після релізу — моніторинг помилок (Sentry) і логів.
Якщо знайшли баг, спочатку пишуть тест, який його відтворює, а потім виправляють.
JuniorПроцеси й AI
Розкажіть про технічну проблему, яку ви вирішили самостійно. Як ви знайшли причину та перевірили результат?
Приклад відповіді
Це поведінкове питання: відповідь має бути власною історією за схемою «ситуація — дії — результат». Наприклад:
«Сторінка замовлень в адмінці завантажувалася 8 секунд. Я ввімкнув Debugbar і побачив понад 300 SQL-запитів — класична N+1 при виведенні клієнтів і товарів. Додав with() для зв'язків і індекс на orders.status. Кількість запитів зменшилася до 4, сторінка відкривається менше ніж за секунду. Щоб проблема не повернулася, увімкнув preventLazyLoading() у режимі розробки».
Важливо показати хід думок і як ви перевірили результат, а не лише фінальне рішення.
MiddleSQL і бази даних
Що таке проблема N+1 і як її виявити та виправити в Laravel?
Приклад відповіді
N+1 виникає, коли для списку з N записів виконується ще N окремих запитів для пов'язаних даних. Наприклад, виводимо 50 замовлень і для кожного окремо запитуємо клієнта — 51 запит замість двох.
Виправляють жадібним завантаженням: Order::with('customer')->get(). Виявити допомагають Laravel Debugbar, Telescope або Model::preventLazyLoading() у режимі розробки — тоді лінивий запит кидає виняток.
MiddleLaravel
Як працює Service Container у Laravel?
Приклад відповіді
Service Container — це контейнер залежностей: він знає, як створювати об'єкти, і автоматично передає їх у конструктори через type-hint. Якщо клас залежить від інтерфейсу, у сервіс-провайдері вказують, яку реалізацію підставити: $this->app->bind(PaymentGateway::class, StripeGateway::class).
bind створює новий об'єкт щоразу, singleton — один на запит (або на весь процес у Octane). Це спрощує тестування: у тесті реалізацію можна замінити на фейк.
MiddleLaravel
Навіщо потрібні черги і що робити, якщо job падає?
Приклад відповіді
Черги виносять повільні завдання з HTTP-запиту: відправку листів, генерацію PDF, звернення до зовнішніх API. Користувач отримує відповідь одразу, а worker обробляє задачу у фоні.
Для надійності задають $tries і backoff, роблять job ідемпотентним (повторний запуск не створює дублікатів), а невдалі задачі потрапляють у failed_jobs. Для моніторингу використовують Horizon, а для ланцюжків — Bus::chain чи Bus::batch.
MiddlePHP 8.x і ООП
Які нові можливості PHP 8.x ви використовуєте в роботі?
Приклад відповіді
Сильна відповідь — з прикладами з власного коду:
enum замість констант для статусів замовлення;
readonly властивості й класи для DTO та value objects;
match замість громіздких switch;
named arguments і constructor property promotion;
у PHP 8.4 — property hooks та асиметрична видимість (public private(set)), а в PHP 8.5 — pipe-оператор |>.
Варто згадати, як ви оновлювали проєкт на нову версію: Rector, PHPStan і тести допомагають зробити це безпечно.
SeniorАрхітектура й безпека
Як би ви спроєктували систему, що витримує різке зростання навантаження (наприклад, розпродаж)?
Приклад відповіді
Почати варто з вимірювань: де вузьке місце — БД, CPU чи зовнішні сервіси. Далі типові кроки:
кешування каталогу й сторінок (Redis, HTTP-кеш, CDN);
черги для всього, що не обов'язково робити синхронно;
репліки БД для читання, індекси, а для складу — атомарні операції або блокування, щоб не продати більше, ніж є;
горизонтальне масштабування застосунку без стану (сесії в Redis), Octane чи RoadRunner для швидкодії;
rate limiting і деградація некритичних функцій.
Обов'язково — навантажувальне тестування (k6) до розпродажу й метрики (OpenTelemetry, Grafana) під час нього.
SeniorАрхітектура й безпека
Моноліт чи мікросервіси: як ви ухвалюєте таке рішення?
Приклад відповіді
Мікросервіси вирішують організаційні проблеми — незалежні релізи великих команд, — але додають мережеві збої, розподілені транзакції й складність інфраструктури. Для більшості продуктів краще стартувати з модульного моноліту: чіткі межі модулів, власні моделі даних, взаємодія через інтерфейси чи події.
Виділяти сервіс варто, коли є чітка причина: інші вимоги до масштабування, окрема команда, інший стек. Добра відповідь на співбесіді — з прикладом, коли ви розділяли або, навпаки, об'єднували сервіси і що з цього вийшло.
SeniorПроцеси й AI
Як ваша команда використовує AI-асистентів у розробці і як контролює якість такого коду?
Приклад відповіді
У 2026 році це вже стандартне питання. Добра відповідь показує баланс: AI-асистенти (Copilot, Cursor, Claude) пришвидшують шаблонний код, тести, міграції й розбір чужого коду, але відповідальність за результат лишається на розробнику.
Контроль якості — ті самі правила, що й для людського коду: обов'язкове код-рев'ю, тести, статичний аналіз (PHPStan на високому рівні), заборона передавати в зовнішні моделі секрети й персональні дані клієнтів. Корисно навести приклад, де AI помилився і як ви це виявили.
SeniorSQL і бази даних
Як безпечно змінити схему великої таблиці (десятки мільйонів рядків) без простою?
Приклад відповіді
Пряма зміна колонки може заблокувати таблицю на хвилини. Підхід expand–contract:
додати нову колонку чи таблицю, не чіпаючи стару;
писати дані в обидва місця, а старі записи переносити фоновою задачею частинами;
переключити читання на нову структуру й перевірити;
видалити стару колонку окремим релізом.
Для MySQL допомагають онлайн-DDL (ALGORITHM=INPLACE), gh-ost або pt-online-schema-change. Важливо мати план відкату й перевірити міграцію на копії продакшн-даних.
Нічого не знайдено. Спробуйте інший запит або рівень.
Типові помилки кандидатів
Відповідати визначеннями з документації без прикладів із власних проєктів.
Не знати нічого про версії PHP новіші за 7.4 — це сигнал, що досвід застарів.
Плутати авторизацію та автентифікацію, не розуміти основ безпеки.
Казати «я використовую AI для всього», не пояснюючи, як перевіряєте результат.
На практичному завданні мовчки писати код замість того, щоб проговорювати рішення.
Як підготуватися
Підготуйте 2–3 історії про складні задачі: що було, що ви зробили, який результат у цифрах.
Повторіть SQL: індекси, JOIN, транзакції — їх питають на будь-якому рівні.
Перегляньте, що нового в PHP 8.4–8.5 і останній версії Laravel.
Майте відкритий pet-проєкт або приклад коду на GitHub, який не соромно показати.
Підготуйте питання до компанії: процес релізів, код-рев'ю, технічний борг.
Cookies допомагають сайту працювати коректно, запам’ятовувати налаштування та аналізувати
відвідуваність.
Продовжуючи, ви погоджуєтесь з
політикою конфіденційності.