Питання на співбесіді рівня Senior
Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів
41 питань
Telescope - інструмент дебагу/спостереження. Збирає й показує у дашборді: запити, винятки, SQL-запити (з часом і дублями), завдання черг, листи, нотифікації, кеш, події, HTTP-клієнт.
php artisan telescope:install
- Незамінний для пошуку N+1 (бачиш усі запити сторінки), повільних місць, помилок у чергах.
- Дані зберігаються в БД; у проді обмежують доступ через gate
viewTelescopeта вмикають sampling, бо обсяг записів великий.
На відміну від Horizon (керування чергами), Telescope - про діагностику всього застосунку. У продакшені часто доповнюють зовнішнім APM (Sentry, Datadog).
У кластері з кількох інстансів локальний лічильник не годиться - потрібен спільний стан у Redis. Фасад RateLimiter під капотом використовує атомарні операції Redis (INCR + EXPIRE), тож підрахунок точний між усіма серверами.
RateLimiter::attempt(
key: 'send-sms:'.$user->id,
maxAttempts: 5,
callback: fn () => $this->sendSms(),
decaySeconds: 60,
);
Для складніших схем - алгоритми sliding window чи token bucket на Lua-скриптах (атомарність на стороні Redis, без гонок). Ключове: лічильник і його TTL мають змінюватися атомарно, інакше за конкурентного доступу ліміт «протікає».
Circuit Breaker захищає від каскадних збоїв при зверненні до ненадійної залежності (зовнішнє API, що «лежить»). Якщо помилок забагато - «ланцюг розривається», і запити певний час відхиляються миттєво, не витрачаючи ресурси на марні спроби.
Стани:
- Closed - усе працює, запити йдуть.
- Open - поріг помилок перевищено; запити одразу падають (fail fast).
- Half-Open - через таймаут пропускаються пробні запити; успіх → Closed, провал → знову Open.
// концептуально через Cache як лічильник збоїв
if (Cache::get('cb:payments') === 'open') {
throw new ServiceUnavailableException;
}
У Laravel реалізують через лічильники в Redis/Cache або пакети-обгортки HTTP-клієнта. Часто поєднують із retry + backoff.
CI автоматично перевіряє кожен пуш, CD - автоматично доставляє код.
Типовий пайплайн (GitHub Actions / GitLab CI):
- composer install
- vendor/bin/pint --test # стиль
- vendor/bin/phpstan analyse # статичний аналіз
- php artisan test --parallel # тести
- npm ci && npm run build # ассети
# → деплой при успіху
Деплой: SSH-скрипт, Docker-образ у реєстрі + rolling update у Kubernetes, або сервіси на кшталт Forge/Envoyer. На етапі деплою - migrate --force, кешування конфіга/маршрутів, queue:restart. CI/CD дає швидкий зворотний зв'язок і знижує ризик людської помилки при релізі.
- Stateful - сервер зберігає стан клієнта між запитами (наприклад, сесія у файлі/пам'яті конкретного інстансу). Тоді потрібна «липкість» (sticky sessions) або спільне сховище.
- Stateless - сервер не зберігає стану; кожен запит самодостатній і містить усе потрібне (наприклад, JWT/токен з даними автентифікації).
Stateful: сесія на сервері → потрібен спільний Redis/sticky LB
Stateless: токен у запиті → будь-який інстанс обробить запит
Stateless легше масштабувати горизонтально - інстанси взаємозамінні. У Laravel веб-частина зазвичай stateful (сесії в Redis), API - stateless (Sanctum-токени). Для масштабування цей стан виносять у спільні Redis/БД.
Sharding - горизонтальне розбиття даних між кількома незалежними БД (шардами) за ключем (tenant_id, user_id, geo). Дозволяє вийти за межі одного сервера.
shard 1: користувачі 1–1M
shard 2: користувачі 1M–2M
- Shard key обирають так, щоб дані рівномірно розподілялись і більшість запитів влучали в один шард.
- Складнощі: запити між шардами, унікальність ID (часто UUID/Snowflake), ребалансування при додаванні шарда, відсутність крос-шардових операцій JOIN і транзакцій.
У Laravel реалізують через множинні з'єднання й маршрутизацію за shard key. Sharding - крайній захід, коли вертикальне масштабування та репліки вже не справляються.
Версіонування дозволяє розвивати API, не ламаючи наявних клієнтів. Стратегії:
URI versioning (найпоширеніше) - версія в шляху:
Route::prefix('v1')->group(base_path('routes/api_v1.php'));
Route::prefix('v2')->group(base_path('routes/api_v2.php'));
Header/Media-type versioning - Accept: application/vnd.app.v2+json. Чистіші URL, але складніше тестувати.
Практики:
- Окремі неймспейси контролерів і API Resources на версію (
V1\PostResource,V2\PostResource). - Бізнес-логіку виносити в спільні Action/Service, щоб не дублювати між версіями.
- Політика deprecation: підтримувати стару версію певний строк, повертати заголовки
Deprecation/Sunset.
Deadlock - дві транзакції взаємно блокують одна одну, чекаючи на ресурси, які тримає інша. СУБД виявляє це й «вбиває» одну з транзакцій.
Запобігання:
- Єдиний порядок доступу до таблиць/рядків у всіх транзакціях.
- Тримати транзакції короткими, блокувати якомога пізніше.
- Правильні рівні ізоляції (не завищувати без потреби).
Обробка в Laravel - автоматичний повтор:
DB::transaction(function () {
// ...
}, attempts: 3); // повторити при deadlock
Діагностика: SHOW ENGINE INNODB STATUS (MySQL), логи БД, моніторинг частоти deadlock. Інколи допомагає optimistic locking замість тривалих блокувань.
Serverless виконує код без керування серверами: провайдер (AWS Lambda) сам масштабує під навантаження й тарифікує за фактичні виклики.
Laravel Vapor - платформа для деплою Laravel на AWS Lambda + API Gateway, з керованими БД, чергами (SQS), кешем і CDN.
Особливості й обмеження:
- Авто-масштабування до нуля й під пік; платиш лише за використання.
- Cold start - затримка першого запиту після простою.
- Файлова система ефемерна → файли лише в S3.
- Обмеження часу виконання Lambda → довгі задачі в черги.
- Stateless за дизайном (сесії/кеш у Redis/DynamoDB).
Альтернатива - контейнери (ECS/Kubernetes), коли потрібен повний контроль або стабільні довготривалі процеси.
WebSocket - постійне двостороннє з'єднання поверх одного TCP, що дає реальний час без поллінгу.
У Laravel сервер WebSockets - Reverb (офіційний), Soketi або Pusher; події транслюються через Broadcasting, клієнт слухає через Echo.
Масштабування: коли інстансів WebSocket-сервера кілька, клієнти на різних інстансах не «бачать» одне одного. Рішення - Redis Pub/Sub як спільна шина: інстанс публікує повідомлення в Redis, усі інстанси отримують і розсилають своїм підключеним клієнтам.
client A ─ inst 1 ┐
├─ Redis Pub/Sub ─┤
client B ─ inst 2 ┘
Окрема увага: авторизація private/presence-каналів, ліміти відкритих з'єднань, sticky sessions на балансувальнику.
2FA вимагає двох факторів: «що знаю» (пароль) + «що маю» (код із застосунку/SMS). Найпоширеніше - TOTP (Time-based One-Time Password) сумісно з Google Authenticator.
У Laravel найпростіше через Fortify, який має 2FA з коробки:
- генерація секрету й QR-коду для прив'язки;
- перевірка 6-значного коду при вході;
- одноразові recovery codes на випадок втрати пристрою.
// Fortify вмикає features:
Features::twoFactorAuthentication(['confirm' => true]),
Під капотом - пакет pragmarx/google2fa. Важливо: зберігати секрет зашифрованим, давати recovery-коди, за бажанням «запам'ятати пристрій».
Докладніше в документації: Двофакторна автентифікація (Fortify)
Laravel Scout - драйверна абстракція повнотекстового пошуку. Додаєте трейт до моделі - і вона автоматично синхронізується з пошуковим індексом (Meilisearch, Algolia, Elasticsearch, навіть database).
class Post extends Model
{
use Searchable;
public function toSearchableArray(): array
{
return ['title' => $this->title, 'body' => $this->body];
}
}
Post::search('laravel queues')->paginate(15);
- Індекс оновлюється на події моделі (краще - через чергу).
- Початкове наповнення:
php artisan scout:import "App\Models\Post". - Meilisearch дає швидкий typo-tolerant пошук «з коробки»; Elasticsearch - складніші аналітичні запити.
Value Object - невеликий незмінний (immutable) об'єкт, що представляє концепцію домену й порівнюється за значенням, а не за ідентичністю (на відміну від Entity з id).
final class Money
{
public function __construct(
public readonly int $cents,
public readonly string $currency,
) {}
public function add(Money $other): self
{
return new self($this->cents + $other->cents, $this->currency);
}
}
Переваги: інкапсуляція правил (валюта, валідація email), самодокументований код, безпека (незмінність). У Laravel VO зручно зберігати через Custom Casts, перетворюючи між колонкою БД та об'єктом.
CSP - HTTP-заголовок, що визначає, з яких джерел дозволено завантажувати ресурси (скрипти, стилі, зображення). Це потужний захист від XSS: навіть якщо зловмисник впровадить <script>, браузер не виконає його, якщо джерело не дозволене.
Content-Security-Policy: default-src 'self';
script-src 'self' https://cdn.example.com;
img-src 'self' data:;
У Laravel заголовок додають через middleware (вручну або пакетом на кшталт spatie/laravel-csp).
Практики:
- Уникати
'unsafe-inline'- використовувати nonce для інлайн-скриптів. - Спершу режим report-only (
Content-Security-Policy-Report-Only) зі збором звітів, щоб не зламати сайт.
BDD розширює TDD, зміщуючи фокус на поведінку системи з погляду бізнесу/користувача, а не на технічні деталі. Сценарії описують зрозумілою мовою (Gherkin: Given-When-Then).
Scenario: Успішний вхід
Given користувач зареєстрований
When він вводить правильні дані
Then він потрапляє на дашборд
У PHP-екосистемі - Behat. Pest також заохочує «describe behavior» стиль:
it('redirects to dashboard after login', function () {
// ...
});
Цінність BDD - спільна мова між розробниками, QA та бізнесом; тести стають живою документацією очікуваної поведінки.