Skip to content

DevLoversTeam/php-interview-questions

Read in other languages: English 🇺🇸, Polska 🇵🇱, German 🇩🇪, French 🇫🇷, Spanish 🇪🇸, Українська 🇺🇦.

PHP PHP logo

Найпопулярніші питання та відповіді на співбесідах з PHP

1. Що таке PHP і які проблеми воно вирішує в сучасній backend-розробці?

PHP

PHP — це серверна мова програмування, створена насамперед для веб-розробки. У сучасній backend-розробці PHP вирішує кілька практичних задач:

  1. Швидка розробка HTTP-бекенду: PHP дозволяє швидко створювати API, вебзастосунки та серверно-рендерені сторінки.

  2. Обробка запитів і бізнес-логіки: Вона приймає вхідні HTTP-запити, валідує дані, виконує бізнес-правила та повертає відповіді.

  3. Інтеграція з базами даних: PHP має зрілий інструментарій для роботи з БД (MySQL, PostgreSQL, SQLite) через PDO та ORM.

  4. Сесії та автентифікація: Підтримує користувацькі сесії, системи логіну, роботу з cookie та контроль доступу.

  5. Екосистема для production-застосунків: Фреймворки на кшталт Laravel і Symfony надають маршрутизацію, dependency injection, черги, події та тестову інфраструктуру.

  6. Фонова обробка: PHP може виконувати асинхронні задачі через черги (email, звіти, сповіщення, імпорти) поза потоком request-response.

  7. Масштабування в реальних системах: З OPcache, шарами кешування (Redis), контейнерами та горизонтальним масштабуванням PHP працює у високонавантажених системах.

  8. Інтеграція із зовнішніми сервісами: PHP широко використовується для платіжних шлюзів, брокерів повідомлень, сторонніх API та хмарних сервісів.

Коротко: PHP покриває повний backend-цикл — приймання запитів, обробку даних, взаємодію зі сховищами та надання безпечних, підтримуваних вебсервісів.

2. Які ключові відмінності між PHP та JavaScript (runtime, модель виконання)?

PHP

PHP і JavaScript широко використовуються у веб-розробці, але суттєво відрізняються за моделлю runtime, потоком виконання і типовою backend-поведінкою.

  1. Основне середовище виконання: PHP працює на сервері (PHP-FPM, CLI, Swoole/RoadRunner), тоді як JavaScript працює у браузері й на сервері через Node.js/Deno/Bun.

  2. Модель виконання (класична): Традиційний PHP — request-per-process/request-per-worker: кожен HTTP-запит стартує, виконується і завершується з ізольованим станом. JavaScript (Node.js) зазвичай працює як довгоживучий процес зі спільним in-memory станом.

  3. Модель конкурентності: У PHP конкурентність зазвичай досягається кількома workers/processes, що обробляють запити паралельно. Серверні runtime JavaScript використовують event loop з async I/O та неблокуючими операціями в одному процесі (плюс worker threads/масштабування процесами за потреби).

  4. Життєвий цикл стану: У класичному PHP in-memory стан не є довговічним між запитами, тому постійний стан зазвичай зберігається в Redis/DB/cache. У Node.js пам’ять процесу може зберігатися між запитами, що зручно, але вимагає обережного керування станом.

  5. Типова веб-роль: PHP традиційно backend-first (SSR, API, бізнес-логіка). JavaScript за природою full-stack: мова frontend UI плюс опція для backend.

  6. Фокус екосистеми: Екосистема PHP робить акцент на backend-фреймворках (Laravel, Symfony), серверних шаблонах і enterprise-веббекендах. Екосистема JavaScript сильно акцентує frontend-фреймворки плюс універсальний/full-stack інструментарій.

  7. Операційний профіль: PHP часто деплоїться за Nginx/Apache з пулами PHP-FPM. JavaScript-бекенди зазвичай деплояться як довгоживучі процеси застосунку за reverse proxy.

На практиці PHP зазвичай обирають за передбачувану ізоляцію запитів і зрілі backend-фреймворки, а JavaScript — коли команді потрібна одна мова для frontend і backend з async-by-default серверною розробкою.

3. Які основні можливості були додані в PHP 8.x (8.1–8.5)?

PHP

У PHP 8.1–8.5 з’явилися важливі покращення мови та runtime. Ключові зміни за версіями:

  1. PHP 8.1 (реліз 25 листопада 2021): Enums, readonly-властивості, fibers, синтаксис callable першого класу, intersection types і тип повернення never.

  2. PHP 8.2 (реліз 8 грудня 2022): Readonly-класи, DNF-типи, окремі типи null/false/true, нове розширення Random і deprecation dynamic properties.

  3. PHP 8.3 (реліз 23 листопада 2023): Типізовані константи класів, атрибут #[\Override], динамічний доступ до констант класу (Class::{$name}) і покращення readonly/clone-поведінки.

  4. PHP 8.4 (реліз 21 листопада 2024): Property hooks, асиметрична видимість (public private(set)-стиль), атрибут #[\Deprecated], оновлений DOM API і підтримка lazy objects.

  5. PHP 8.5 (реліз 20 листопада 2025): Pipe-оператор (|>), URI-розширення, оновлення через clone(...), #[\NoDiscard], closure у константних виразах та додаткові runtime/API-покращення.

Чому це важливо

  • Краща типобезпека: сильніша типізація, надійніші контракти, менше неочікуваних помилок під час виконання.
  • Чистіше моделювання домену: enums, readonly-конструкції та сучасна робота з властивостями.
  • Виразніший код: pipe-оператор, атрибути й краща підтримка callable.
  • Продуктивність і підтримуваність: постійна еволюція engine, інструментів і стандартної бібліотеки.

Коротко: PHP 8.x суттєво осучаснив мову і спростив побудову та підтримку сучасної backend-архітектури.

4. Що таке enums, attributes і readonly-властивості в PHP?

PHP

Enums, attributes і readonly-властивості — це сучасні можливості мови PHP, які підвищують коректність, читабельність і підтримуваність коду.

  1. Enums
  • Enum визначає фіксований набір допустимих значень як окремий тип.
  • Це запобігає невалідним string/int-станам і робить моделювання домену безпечнішим.
  • У PHP підтримуються: backed enums (enum Status: string { ... }) і unit enums (enum Role { ... }).
enum OrderStatus: string
{
    case Draft = 'draft';
    case Paid = 'paid';
    case Shipped = 'shipped';
}
  1. Attributes
  • Attributes — це нативні метадані (#[...]), які можна прикріплювати до класів, методів, властивостей, параметрів тощо.
  • Вони замінюють багато сценаріїв docblock-анотацій структурованими, машинозчитуваними метаданими.
  • Типові кейси: маршрутизація, валідація, dependency injection, правила серіалізації, позначки deprecation.
#[Deprecated(reason: 'Use NewService instead')]
class LegacyService {}
  1. Readonly-властивості
  • readonly-властивість можна записати лише один раз (зазвичай у конструкторі).
  • Після ініціалізації змінювати її не можна.
  • Це корисно для immutable DTO, value objects і безпечнішого дизайну об’єктів.
final class UserDto
{
    public function __construct(
        public readonly int $id,
        public readonly string $email,
    ) {}
}

Чому вони важливі разом

  • Enums захищають допустимі стани.
  • Attributes додають явні метадані для фреймворків та інструментів.
  • Readonly-властивості забезпечують незмінність критичних даних.

Разом ці можливості зменшують кількість багів, роблять API зрозумілішими та покращують якість статичного аналізу в сучасних PHP-кодових базах.

5. Що таке strict typing у PHP і чому це важливо?

PHP

Strict typing у PHP вмикається для кожного файлу окремо через:

declare(strict_types=1);

Коли strict typing увімкнений, декларації скалярних типів перевіряються суворіше для аргументів функцій і значень, що повертаються.

  1. Без strict types (strict_types=0, за замовчуванням): PHP може виконувати неявне приведення скалярів (наприклад, '10' до 10), якщо це можливо.

  2. З strict types (strict_types=1): PHP викидає TypeError замість тихого перетворення несумісних скалярних значень.

declare(strict_types=1);

function add(int $a, int $b): int
{
    return $a + $b;
}

add('2', 3); // TypeError у strict-режимі

Чому це важливо

  • Раннє виявлення помилок: невідповідності типів падають одразу.
  • Безпечніший рефакторинг: чіткі контракти зменшують ризик прихованих зламів.
  • Передбачуваніша поведінка: менше неявної магії з приведенням типів.
  • Кращий статичний аналіз: інструменти на кшталт PHPStan/Psalm працюють ефективніше.
  • Чистіші межі API: сигнатури функцій трактуються як суворі контракти.

Практична рекомендація

Використовуйте declare(strict_types=1); у всіх нових PHP-файлах і поєднуйте це з явними type hints, DTO/value objects та статичним аналізом для production-рівня надійності.

6. Що таке union та intersection types?

PHP

Union та intersection types у PHP — це інструменти для вираження суворіших і більш явних типових контрактів.

  1. Union types (A|B)
  • Значення може мати один із кількох дозволених типів.
  • Це корисно, коли аргумент або значення, що повертається, легітимно може відрізнятися.
function formatId(int|string $id): string
{
    return (string) $id;
}
  1. Intersection types (A&B)
  • Значення має відповідати всім переліченим типам одночасно.
  • Часто використовується з інтерфейсами, щоб вимагати кілька можливостей одразу.
interface Cacheable {}
interface Jsonable { public function toJson(): string; }

function store(Cacheable&Jsonable $entity): void
{
    // $entity має реалізовувати обидва інтерфейси
}
  1. Ключова різниця
  • A|B означає або A, або B.
  • A&B означає A і B разом.
  1. Чому це важливо
  • Кращі API-контракти та самодокументований код.
  • Менше runtime-помилок через невалідні форми об’єктів/значень.
  • Сильніший статичний аналіз і безпечніший рефакторинг.
  1. Практичні поради
  • Використовуйте union types для гнучких вхідних меж.
  • Використовуйте intersection types для дизайну за можливостями (особливо з інтерфейсами).
  • За можливості віддавайте перевагу конкретним типам замість mixed.
7. Що таке nullsafe-оператор і коли його використовувати?

PHP

Nullsafe-оператор у PHP — це ?->. Він дозволяє безпечно звертатися до методів/властивостей об’єктів, які можуть бути null.

  1. Що він робить
  • Якщо зліва об’єкт, доступ виконується звичайно.
  • Якщо зліва null, обчислення зупиняється і повертається null замість помилки.
$country = $user?->getProfile()?->getAddress()?->country;
  1. Чому це корисно
  • Прибирає громіздкі вкладені перевірки на null.
  • Зменшує boilerplate у ланцюгах опціональних об’єктів.
  • Робить намір коду зрозумілішим, коли nullable-значення є нормою.
  1. Типові сценарії використання
  • API/DTO-структури з опціональними вкладеними полями.
  • ORM-зв’язки, які можуть бути відсутні.
  • Об’єкти контексту запиту, де окремі частини опціональні.
  1. Еквівалент без nullsafe (більш багатослівний)
$country = null;
if ($user !== null) {
    $profile = $user->getProfile();
    if ($profile !== null) {
        $address = $profile->getAddress();
        if ($address !== null) {
            $country = $address->country;
        }
    }
}
  1. Важливі зауваження
  • ?-> працює лише для доступу до об’єктів (методи/властивості), не для індексів масивів.
  • Оператор short-circuit виконується зліва направо.
  • Якщо ланцюг завершується на null, фінальний результат теж null.

Використовуйте nullsafe-оператор, коли null є очікуваним станом і потрібен лаконічний, безпечний обхід графа об’єктів.

8. Що таке property hooks (PHP 8.4+)?

PHP

Property hooks (додані в PHP 8.4) дозволяють прикріплювати логіку прямо до операцій читання/запису властивостей через хуки get і set.

  1. Яку проблему вони вирішують
  • Зменшують boilerplate-код getter/setter-методів.
  • Тримають валідацію/трансформацію поруч із визначенням властивості.
  • Дають змогу оголошувати обчислювані (віртуальні) властивості з чистішим синтаксисом.
  1. Базова ідея
class User
{
    public string $name {
        set => trim($value);
    }
}

Будь-яке присвоєння в $user->name проходить через set-hook.

  1. Приклад обчислюваної властивості
class Person
{
    public function __construct(
        public string $firstName,
        public string $lastName,
    ) {}

    public string $fullName {
        get => $this->firstName . ' ' . $this->lastName;
    }
}

$fullName обчислюється з інших полів і не потребує ручних getter-методів.

  1. Приклад валідації/трансформації
class Product
{
    public float $price {
        set {
            if ($value < 0) {
                throw new InvalidArgumentException('Price cannot be negative');
            }
            $this->price = round($value, 2);
        }
    }
}
  1. Коли використовувати
  • Доменні сутності зі строгими інваріантами.
  • DTO/value-like об’єкти, де потрібен контрольований запис.
  • Сценарії, де старий стиль get/set був здебільшого boilerplate.

Property hooks роблять об’єктні моделі виразнішими та зменшують повторюваний accessor-код, зберігаючи сильну валідацію й інкапсуляцію.

9. Що таке pipe-оператор (PHP 8.5) і коли він корисний?

PHP

Pipe-оператор у PHP 8.5 — це |>. Він передає результат виразу зліва у callable справа, що дозволяє будувати читабельні перетворення даних зліва направо.

  1. Базова ідея

Замість глибоко вкладених викликів можна побудувати лінійний pipeline обробки.

$result = " Hello World "
    |> trim(...)
    |> strtolower(...)
    |> (fn(string $s) => str_replace(' ', '-', $s));
  1. Чому це корисно
  • Покращує читабельність багатокрокових трансформацій.
  • Зменшує кількість тимчасових змінних.
  • Дозволяє уникнути вкладених викликів функцій «навиворіт».
  • Полегшує рефакторинг ланцюгів перетворення.
  1. До і після

Без pipe:

$slug = strtolower(str_replace(' ', '-', trim($title)));

З pipe:

$slug = $title
    |> trim(...)
    |> (fn(string $s) => str_replace(' ', '-', $s))
    |> strtolower(...);
  1. Вдалі сценарії використання
  • Ланцюги нормалізації рядків/даних.
  • Потоки мапінгу/трансформації DTO.
  • Функціональний стиль обробки даних у сервісах.
  1. Практична примітка

Використовуйте pipe-оператор для чітких послідовних трансформацій. Для складної розгалуженої логіки звичайні проміжні змінні можуть залишатися зрозумілішим варіантом.

10. Що таке superglobals у PHP і як вони використовуються?

PHP

Superglobals у PHP — це вбудовані асоціативні масиви, доступні в усіх областях видимості (функції, методи, глобальна область) без використання global.

  1. Основні superglobals
  • $_GET - параметри query string з URL.
  • $_POST - параметри форми/body з POST-запитів.
  • $_REQUEST - об’єднані дані запиту (залежить від request_order/variables_order).
  • $_SERVER - метадані сервера й запиту (headers, method, URI, host тощо).
  • $_COOKIE - cookies клієнта, передані в запиті.
  • $_SESSION - сесійні дані, що зберігаються між запитами.
  • $_FILES - метадані завантажених файлів.
  • $_ENV - змінні середовища.
  • $GLOBALS - посилання на всі глобальні змінні.
  1. Типові приклади використання
$page = $_GET['page'] ?? 'home';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$token = $_COOKIE['csrf_token'] ?? null;
  1. Чому це важливо
  • Це основний інтерфейс між PHP-кодом і HTTP/runtime-середовищем.
  • Вони надають вхідні дані запиту, контекст і збережений стан користувача/сесії.
  1. Практики безпеки та надійності
  • Ніколи не довіряйте вхідним даним із superglobals напряму.
  • Завжди валідуйте й санітизуйте зовнішні дані.
  • Використовуйте строгі перевірки та значення за замовчуванням (??, filter_input, валідатори).
  • У критичному коді уникайте залежності від $_REQUEST, бо пріоритет джерел може відрізнятися.
  • Екрануйте вивід для запобігання XSS та використовуйте prepared statements проти SQL injection.

Superglobals є фундаментом PHP-веброзробки, але їх завжди слід розглядати як недовірену межу вводу.

11. Яка різниця між GET і POST запитами?

PHP

GET і POST — це HTTP-методи з різною семантикою та сценаріями використання.

  1. Призначення
  • GET використовується для отримання даних (операції лише читання).
  • POST використовується для надсилання даних, які можуть змінювати стан сервера (create/process-операції).
  1. Де передаються дані
  • GET передає параметри в query string URL (/users?page=2).
  • POST передає дані в тілі запиту.
  1. Видимість і логування
  • Параметри GET видимі в URL, історії браузера, логах і referrer.
  • Тіло POST не відображається в URL, але все одно має розглядатися як недовірений ввід.
  1. Кешування і закладки
  • GET-запити добре кешуються і можуть додаватися в закладки.
  • POST-запити зазвичай не кешуються за замовчуванням і не закладаються разом із payload.
  1. Ідемпотентність і безпечність (HTTP-семантика)
  • GET має бути безпечним і не змінювати стан сервера.
  • POST не гарантує ідемпотентність і зазвичай виконує побічні ефекти.
  1. Доступ у PHP
$search = $_GET['q'] ?? null;      // з query string
$email  = $_POST['email'] ?? null; // з тіла запиту
  1. Коли використовувати
  • Використовуйте GET для фільтрації, пошуку, пагінації та читання ресурсів.
  • Використовуйте POST для відправки форм, дій автентифікації та створення/оновлення даних на сервері (або PUT/PATCH, коли це доречно в API).

Ключове правило: GET для read-операцій, POST для операцій зміни стану, з валідацією всіх вхідних даних в обох випадках.

12. Як PHP обробляє HTTP-запити та відповіді?

PHP

У типовій веб-конфігурації PHP обробляє HTTP через життєвий цикл request-response, який координується вебсервером (Nginx/Apache) і PHP-runtime (найчастіше PHP-FPM).

  1. Надходить запит
  • Клієнт надсилає HTTP-запит (method, URI, headers, body).
  • Вебсервер приймає його та маршрутизує динамічні запити до PHP.
  1. PHP-runtime виконує скрипт
  • PHP ініціалізує контекст запиту і заповнює superglobals ($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES).
  • Запускається bootstrap застосунку (autoload, config, DI container, framework kernel).
  1. Застосунок виконує бізнес-логіку
  • Router визначає controller/handler.
  • Працюють middleware/guards/validation.
  • Services/repositories звертаються до бази даних, кешу чи зовнішніх API.
  1. Формується відповідь
  • Застосунок задає status code, headers і body (HTML/JSON/file/stream).
  • У plain PHP це зазвичай робиться через header(), http_response_code() і вивід.
  • У фреймворках зазвичай повертається об’єкт Response, який далі емітиться у відповідь.
http_response_code(200);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['ok' => true], JSON_THROW_ON_ERROR);
  1. Відповідь надсилається
  • PHP передає вивід вебсерверу.
  • Вебсервер відправляє фінальну HTTP-відповідь клієнту.
  • У класичному PHP-FPM стан запиту завершується після відповіді (для персистентності використовують зовнішні сховища).
  1. Обробка помилок
  • Винятки перетворюються на HTTP-помилки (наприклад, 404, 422, 500) framework/global handlers.
  • Логи та моніторинг фіксують збої для подальшої діагностики.

Модель PHP прямолінійна: отримати контекст запиту, виконати код застосунку, сформувати HTTP-відповідь і коректно завершити запит.

13. Як працюють сесії та які практики безпеки сесій є обов’язковими?

PHP

Сесії в PHP дозволяють зберігати стан, специфічний для користувача, між stateless HTTP-запитами: дані зберігаються на сервері й прив’язуються до session ID.

  1. Як працюють сесії
  • Клієнт робить перший запит.
  • Сервер створює session ID (SID).
  • SID відправляється клієнту, зазвичай через cookie (найчастіше PHPSESSID).
  • У наступних запитах клієнт повертає SID.
  • PHP завантажує відповідні серверні сесійні дані в $_SESSION.
  1. Базове використання
session_start();

$_SESSION['user_id'] = 42;
$userId = $_SESSION['user_id'] ?? null;
  1. Де зберігаються дані
  • За замовчуванням: файлова сесійна storage.
  • У production: часто Redis/database/memcached через кастомні handlers для масштабованості.
  1. Безпечні практики сесій
  • Регенеруйте session ID після логіну/зміни привілеїв: session_regenerate_id(true);
  • Використовуйте cookie-прапори: HttpOnly, Secure, SameSite (Lax або Strict, коли можливо).
  • Примусово використовуйте HTTPS для автентифікованих застосунків.
  • Налаштовуйте timeout сесії та неактивності.
  • Інвалідуйте сесію під час logout (очистити дані + destroy session + прострочити cookie).
  • Обережно прив’язуйте сесії до контекстних сигналів (наприклад, часткова перевірка IP/UA), щоб зменшити ризик викрадення.
  • Зберігайте в сесії мінімум чутливих даних; надавайте перевагу ID/посиланням замість повних секретів.
  1. Поширені загрози
  • Session fixation: атакувальник нав’язує відомий SID до автентифікації.
  • Session hijacking: викрадений SID повторно використовується атакувальником.
  • XSS-assisted theft: шкідливі скрипти можуть експлуатувати небезпечну роботу із сесіями.
  1. Чекліст hardening
  • session.use_strict_mode=1
  • session.cookie_httponly=1
  • session.cookie_secure=1 (на HTTPS)
  • Коректний session.cookie_samesite
  • Регулярна ротація SID для автентифікованих flow

Сесії є безпечним і ефективним механізмом, коли session ID захищені, вчасно ротуются та передаються лише довіреними каналами.

14. Як у сучасних застосунках встановлюються та захищаються cookies?

PHP

Cookies — це невеликі key-value дані, які зберігаються в браузері та надсилаються з відповідними запитами. У сучасних застосунках вони використовуються для сесій, налаштувань і безпечних auth-flow.

  1. Як встановлюються cookies у PHP

Використовуйте setcookie() (або response-хелпери фреймворку) до надсилання будь-якого виводу:

setcookie(
    'session_token',
    $token,
    [
        'expires'  => time() + 3600,
        'path'     => '/',
        'domain'   => 'example.com',
        'secure'   => true,
        'httponly' => true,
        'samesite' => 'Lax',
    ]
);
  1. Як читати cookies
$token = $_COOKIE['session_token'] ?? null;
  1. Атрибути безпеки (критично важливо)
  • Secure: cookie надсилається лише через HTTPS.
  • HttpOnly: недоступно з JavaScript (document.cookie), зменшує ризик викрадення через XSS.
  • SameSite: Strict (сильний захист від CSRF), Lax (збалансований), None (потребує Secure, для cross-site сценаріїв).
  • Expires/Max-Age: обмежує час життя.
  • Path/Domain: звужуйте scope cookie максимально вузько.
  1. Найкращі практики
  • Використовуйте HTTPS всюди та завжди ставте Secure для чутливих cookies.
  • Встановлюйте HttpOnly для session/auth cookies.
  • Віддавайте перевагу SameSite=Lax або Strict, якщо cross-site-поведінка явно не потрібна.
  • Ротуйте auth/session токени та коректно задавайте термін їх дії.
  • Не зберігайте чутливі plaintext-дані в cookies.
  • Розглядайте підпис або шифрування payload cookie, якщо стан зберігається на клієнті.
  1. Поширені помилки
  • Відсутній HttpOnly або Secure.
  • Надто широкий domain/path.
  • Дуже довгий термін дії auth-cookies.
  • Довіра до значень cookie без серверної верифікації.

Сучасна безпека cookies базується на строгому scope, захищеному транспорті, безпечних дефолтах і серверній валідації всіх значень, отриманих від клієнта.

15. Що таке CSRF і як його запобігати?

PHP

CSRF (Cross-Site Request Forgery) — це атака, у якій браузер жертви змушують надіслати автентифікований запит до вашого застосунку без наміру користувача.

  1. Як працює CSRF
  • Користувач залогінений у your-app.com.
  • Атакувальник заманює користувача на шкідливу сторінку.
  • Ця сторінка тригерить запит до your-app.com (наприклад, зміна email, переказ коштів).
  • Браузер автоматично додає cookies/session, тому запит може бути прийнятий.
  1. Чому це небезпечно
  • Сервер бачить валідну автентифіковану сесію.
  • Операції зміни стану можуть виконуватися від імені жертви.
  1. Основний захист: CSRF-токен
  • Генеруйте випадковий токен на сесію/запит.
  • Вбудовуйте токен у форми або заголовки запиту.
  • Перевіряйте токен на сервері до обробки дій, що змінюють стан.
session_start();

// Генеруємо токен один раз
$_SESSION['csrf_token'] ??= bin2hex(random_bytes(32));

// Перевіряємо на POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $token = $_POST['_csrf'] ?? '';
    if (!hash_equals($_SESSION['csrf_token'], $token)) {
        http_response_code(419);
        exit('Invalid CSRF token');
    }
}
  1. Додаткові захисти
  • Використовуйте SameSite cookies (Lax/Strict) для зменшення cross-site надсилання cookie.
  • Перевіряйте заголовки Origin/Referer для чутливих endpoint-ів (як defense-in-depth).
  • Вимагайте повторну автентифікацію або step-up підтвердження для критичних операцій.
  • Не використовуйте GET для дій, що змінюють стан.
  1. Найкраща практика у фреймворках
  • Використовуйте вбудований CSRF-middleware (Laravel/Symfony тощо) замість кастомної реалізації, де це можливо.
  • Переконайтесь, що токени присутні в усіх mutating-запитах (POST/PUT/PATCH/DELETE), включно з AJAX.

CSRF-захист є обов’язковим для cookie-based автентифікації і має бути частиною базового security-middleware за замовчуванням.

16. Що таке XSS і як правильно від нього захищатися?

PHP

XSS (Cross-Site Scripting) — це вразливість, за якої дані, контрольовані атакувальником, інтерпретуються браузером як виконуваний скрипт на сторінках вашого застосунку.

  1. Основні типи XSS
  • Stored XSS: шкідливий payload зберігається (БД/коментар/профіль) і пізніше віддається користувачам.
  • Reflected XSS: payload приходить із вхідних даних запиту та одразу відображається у відповіді.
  • DOM-based XSS: клієнтський JavaScript записує небезпечні дані в DOM.
  1. Коренева причина
  • Недовірений ввід потрапляє в HTML/JS/URL/CSS-контекст без коректного output-encoding.
  1. Основний захист: контекстне екранування на виводі
  • Екрануйте дані під час виводу, відповідно до контексту рендерингу.
  • Для текстового HTML-контексту в PHP:
echo htmlspecialchars($userInput, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
  1. Правила для різних контекстів
  • HTML body: htmlspecialchars(...).
  • HTML attributes: також екрануйте лапки (ENT_QUOTES).
  • JavaScript-контекст: передавайте через JSON-encoding, уникайте прямої конкатенації рядків.
  • URL-контекст: використовуйте rawurlencode() для значень параметрів.
  • Уникайте прямого вставлення недовіреного HTML.
  1. Додаткові захисти
  • Використовуйте auto-escaping у templating engine/фреймворку.
  • Санітизуйте rich HTML allowlist-підходом (якщо HTML-ввід справді потрібен).
  • Налаштовуйте сильний Content Security Policy (CSP) як defense-in-depth.
  • За можливості уникайте inline scripts.
  • Валідуйте ввід, але не сприймайте валідацію як заміну output-encoding.
  1. Поширені помилки
  • Екранування вводу один раз і повторне використання в різних контекстах.
  • Глобальне вимкнення template auto-escaping.
  • Рендеринг сирого user-generated content в admin/internal-панелях.

Запобігання XSS базується на строгому контекстному кодуванні в точці виводу, доповненому CSP і безпечними патернами рендерингу.

17. Що таке SQL Injection і як prepared statements його запобігають?

PHP

SQL Injection — це вразливість, за якої ввід атакувальника змінює структуру SQL-запиту, що може призвести до несанкціонованого доступу до даних або їх модифікації.

  1. Як виникає SQL Injection

Він з’являється, коли недовірений ввід напряму конкатенується в SQL-рядок.

// Небезпечний приклад
$sql = "SELECT * FROM users WHERE email = '" . $_POST['email'] . "'";

Атакувальник може вставити SQL-фрагменти і змінити логіку запиту.

  1. Наслідки
  • Обхід автентифікації
  • Витік/модифікація/видалення даних
  • Ескалація привілеїв
  • У важких випадках - повна компрометація бази даних
  1. Як prepared statements запобігають цьому

Prepared statements розділяють:

  • SQL-структуру (шаблон запиту)
  • Дані (параметри, що прив’язуються)

База даних обробляє прив’язані значення як дані, а не як виконуваний SQL-код.

$pdo = new PDO($dsn, $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $_POST['email']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
  1. Важливий нюанс
  • Prepared statements захищають значення, але не динамічні SQL-ідентифікатори (імена таблиць/колонок).
  • Якщо ідентифікатори мають бути динамічними, використовуйте строгі allowlist.
  1. Найкращі практики
  • Використовуйте prepared statements PDO/MySQLi всюди, де є зовнішній ввід.
  • Ніколи не будуйте SQL через конкатенацію рядків із даними користувача.
  • Дотримуйтеся принципу найменших привілеїв для DB-акаунтів.
  • Валідуйте ввід і логайте підозрілу активність.
  • Тримайте DB engine/drivers в актуальному стані.

Prepared statements — основний і обов’язковий захист від SQL injection у сучасних PHP-застосунках.

18. Що таке Content Security Policy (CSP)?

PHP

Content Security Policy (CSP) — це браузерний механізм безпеки, який обмежує, які ресурси (scripts, styles, images, frames тощо) дозволено завантажувати та виконувати на сторінці.

  1. Від чого захищає CSP
  • Передусім зменшує вплив XSS, блокуючи неавторизовані inline/external скрипти.
  • Допомагає знизити ризик ексфільтрації даних через шкідливі завантаження ресурсів.
  • Обмежує ризиковані можливості браузера лише довіреними джерелами.
  1. Як доставляється CSP
  • Зазвичай через HTTP response header: Content-Security-Policy: ...
  • Також можна спочатку вмикати режим звітності: Content-Security-Policy-Report-Only: ...
  1. Базовий приклад
header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'");
  1. Важливі директиви
  • default-src - fallback-політика джерел.
  • script-src - керує джерелами JavaScript.
  • style-src - керує джерелами CSS.
  • img-src - керує джерелами зображень.
  • connect-src - керує XHR/fetch/WebSocket-цілями.
  • frame-ancestors - запобігає clickjacking, контролюючи вбудовування сторінки.
  • object-src 'none' - вимикає legacy plugin-контент.
  • base-uri - обмежує ін’єкцію тега <base>.
  1. Найкращі практики
  • Починайте з Report-Only, збирайте порушення, потім вмикайте enforcement.
  • Для inline-скриптів віддавайте перевагу nonces/hashes замість 'unsafe-inline'.
  • Тримайте політику строгою та явно визначеною для кожного середовища.
  • Поєднуйте CSP з output escaping, CSRF-захистом і secure cookies.
  1. CSP — не срібна куля
  • Це defense-in-depth, а не заміна безпечного кодування.
  • Ви все одно маєте санітизувати/екранувати недовірений вивід і уникати небезпечних DOM-патернів.

CSP суттєво підсилює frontend-безпеку за умови акуратного налаштування і постійного моніторингу.

19. Що таке autoloading і як працює PSR-4?

PHP

Autoloading — це механізм, який автоматично підвантажує файли класів/інтерфейсів/trait у PHP під час їх першого використання, замість ручного написання великої кількості require/include.

  1. Навіщо потрібен autoloading
  • Прибирає ручні підключення файлів.
  • Робить структуру проєкту масштабованою.
  • Полегшує керування залежностями та модулями.
  1. PSR-4 коротко

PSR-4 — це сучасний стандарт мапінгу namespace до шляхів файлової системи.

  • Prefix namespace мапиться на базову директорію.
  • Решта частин namespace мапиться на піддиректорії.
  • Ім’я класу мапиться на ім’я файла (ClassName.php).
  1. Приклад мапінгу

Якщо в Composer-конфігурації є:

{
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  }
}

Тоді:

  • App\Services\UserService -> src/Services/UserService.php
  • App\Http\Controllers\HomeController -> src/Http/Controllers/HomeController.php
  1. Як це вмикає Composer
  • Оголосіть autoload.psr-4 у composer.json.
  • Виконайте:
composer dump-autoload
  • Підключіть Composer autoloader один раз (зазвичай у bootstrap застосунку):
require __DIR__ . '/vendor/autoload.php';
  1. Найкращі практики
  • Дотримуйтесь принципу один клас на файл.
  • Узгоджуйте назви namespace і директорій.
  • Використовуйте осмислений root namespace (App\\, Domain\\, Company\\Project\\).
  • Після змін namespace/шляхів перевегенеровуйте autoload-файли.

Autoloading із PSR-4 — базова основа сучасної структури PHP-застосунків і завантаження залежностей.

20. Що таке Composer і як працює керування залежностями?

PHP

Composer — стандартний менеджер залежностей для PHP. Він встановлює, оновлює та автозавантажує бібліотеки проєкту у відтворюваний спосіб.

  1. Ключові файли
  • composer.json - описує метадані проєкту, потрібні пакети, правила autoload і scripts.
  • composer.lock - фіксує точні версії пакетів, розв’язані для проєкту.
  • vendor/ - встановлені залежності та Composer autoloader.
  1. Як працює керування залежностями
  • Ви задаєте обмеження версій у composer.json (наприклад, ^11.0).
  • Composer розв’язує сумісний граф залежностей.
  • Точні знайдені версії записуються у composer.lock.
  • Команда/CI встановлює саме зафіксовані версії для детермінованих збірок.
  1. Базовий workflow
# Додати залежність
composer require monolog/monolog

# Встановити з lock-файла
composer install

# Оновити залежності (повторно розв'язати constraints)
composer update
  1. Обмеження версій
  • ^1.2 - дозволяє зворотно-сумісні оновлення до <2.0.0.
  • ~1.2.3 - дозволяє patch/minor-оновлення в межах цієї гілки.
  • Точні версії можливі, але для бібліотек зазвичай надто жорсткі.
  1. Інтеграція з autoload

Composer генерує vendor/autoload.php і підтримує PSR-4 мапінг автозавантаження з composer.json.

require __DIR__ . '/vendor/autoload.php';
  1. Найкращі практики
  • Комітьте composer.lock для застосунків.
  • Використовуйте composer install у CI/production.
  • Запускайте composer update усвідомлено та переглядайте зміни в lock-файлі.
  • Віддавайте перевагу стабільним версіям пакетів.
  • Регулярно перевіряйте залежності (composer audit).

Composer є критично важливим у сучасному PHP, бо стандартизує керування пакетами, autoload і відтворювані збірки між середовищами.

21. Що таке стандарти PSR і чому вони важливі?

PHP

PSR (PHP Standards Recommendations) — це спільнотні стандарти, опубліковані PHP-FIG (PHP Framework Interop Group), щоб покращити інтероперабельність і узгодженість між PHP-бібліотеками та фреймворками.

  1. Що визначають PSR
  • Конвенції стилю коду (наприклад, PSR-12).
  • Конвенції автозавантаження (PSR-4).
  • Спільні інтерфейси для HTTP-повідомлень, middleware, контейнерів, логування, кешування тощо.
  1. Чому вони важливі
  • Інтероперабельність: бібліотеки від різних вендорів легше працюють разом.
  • Передбачуваність: знайомі інтерфейси та структура між проєктами.
  • Підтримуваність: командні кодові бази консистентніші та легші для рев’ю.
  • Портативність між фреймворками: менший vendor lock-in, коли архітектура будується на стандартних контрактах.
  1. PSR, які найчастіше використовуються
  • PSR-1 / PSR-12 - базовий та розширений стиль коду.
  • PSR-3 - інтерфейс логера (LoggerInterface).
  • PSR-4 - стандарт автозавантаження.
  • PSR-6 / PSR-16 - інтерфейси кешування.
  • PSR-7 - інтерфейси HTTP-повідомлень (Request/Response/Stream).
  • PSR-11 - інтерфейс контейнера.
  • PSR-15 - HTTP server request handlers і middleware.
  • PSR-18 - інтерфейс HTTP-клієнта.
  1. Практичний ефект у реальних проєктах
  • Можна замінювати реалізації (наприклад, logger/client/container) без переписування бізнес-логіки.
  • Фреймворки та пакети швидше інтегруються завдяки спільним інтерфейсам.
  • Інструменти (лінтери/статичні аналізатори/framework adapters) легше впроваджувати.

PSR — це не просто гайдлайни стилю; це архітектурні контракти, які роблять сучасну PHP-екосистему композиційною та стійкою.

22. Що таке PSR-7 (HTTP-повідомлення)?

PHP

PSR-7 — це стандарт, який визначає інтерфейси для HTTP-повідомлень у PHP: запити, відповіді, потоки та завантажені файли.

  1. Що стандартизує PSR-7
  • ServerRequestInterface - вхідний HTTP-запит із клієнтського/серверного контексту.
  • RequestInterface - узагальнений вихідний запит.
  • ResponseInterface - HTTP-відповідь (status, headers, body).
  • StreamInterface - абстракція тіла повідомлення.
  • UploadedFileInterface - абстракція завантаженого файлу.
  • UriInterface - представлення URI.
  1. Чому це важливо
  • Надає спільний контракт між фреймворками та бібліотеками.
  • Дає змогу будувати middleware-пайплайни та перевикористовувані HTTP-компоненти.
  • Зменшує vendor lock-in завдяки кодуванню під інтерфейси, а не під конкретні класи фреймворку.
  1. Принцип незмінності (immutability)

PSR-7 повідомлення є immutable. Методи на кшталт withHeader() повертають новий екземпляр, а не змінюють оригінальний об’єкт.

$newResponse = $response
    ->withStatus(201)
    ->withHeader('Content-Type', 'application/json');
  1. Типове використання
  • У middleware та handlers (часто разом із PSR-15).
  • В API-фреймворках для парсингу запиту та генерації відповіді.
  • В HTTP-клієнтах/серверах, що обмінюються стандартизованими об’єктами повідомлень.
  1. Практична користь

Компонент, написаний під PSR-7, зазвичай можна перевикористати в різних екосистемах (Slim, Laminas, Symfony bridges, Mezzio тощо) з мінімальною адаптацією.

PSR-7 — ключовий шар інтероперабельності для роботи з HTTP-повідомленнями в сучасних PHP-застосунках.

23. Що таке PSR-11 (контейнер залежностей)?

PHP

PSR-11 — це стандартний інтерфейс для контейнерів dependency injection у PHP. Він визначає, як код застосунку отримує сервіси з контейнера у framework-agnostic спосіб.

  1. Базові інтерфейси PSR-11
  • Psr\Container\ContainerInterface
  • Psr\Container\ContainerExceptionInterface
  • Psr\Container\NotFoundExceptionInterface

Основні методи:

  • get(string $id): mixed
  • has(string $id): bool
  1. Яку проблему це вирішує
  • Стандартизує доступ до контейнера між бібліотеками/фреймворками.
  • Дозволяє компонентам залежати від спільного контракту замість конкретних реалізацій контейнера.
  • Покращує інтероперабельність і портативність.
  1. Простий приклад використання
use Psr\Container\ContainerInterface;

function run(ContainerInterface $container): void
{
    if ($container->has('logger')) {
        $logger = $container->get('logger');
        $logger->info('Started');
    }
}
  1. Важлива ремарка по дизайну

PSR-11 визначає як читати сервіси, але не як їх реєструвати/будувати. API реєстрації залежать від конкретного контейнера.

  1. Найкращі практики
  • У коді застосунку віддавайте перевагу constructor injection.
  • Прямий lookup у контейнері використовуйте переважно в infrastructure/bootstrap-шарах.
  • Уникайте антипатерну Service Locator у domain/business logic.
  • По можливості type-hint інтерфейси, а не конкретні реалізації.

PSR-11 — мінімальний, але важливий стандарт, який робить роботу з контейнерами залежностей консистентною в PHP-екосистемі.

24. Що таке PSR-15 (middleware)?

PHP

PSR-15 — це стандарт, який визначає серверні HTTP-middleware та request handlers у PHP. Він працює разом з інтерфейсами запиту/відповіді PSR-7.

  1. Базові інтерфейси PSR-15
  • Psr\Http\Server\MiddlewareInterface
  • Psr\Http\Server\RequestHandlerInterface

Контракти методів:

  • Middleware: process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  • Handler: handle(ServerRequestInterface $request): ResponseInterface
  1. Як працює middleware pipeline
  • Запит входить у ланцюг middleware.
  • Кожен middleware може: валідувати/модифікувати запит, short-circuit з відповіддю або передати запит далі.
  • Фінальний handler генерує відповідь.
  • Відповідь може модифікуватися на зворотному шляху через middleware-стек.
  1. Типові обов’язки middleware
  • Authentication/authorization
  • CORS
  • Logging/tracing
  • Rate limiting
  • Request validation
  • Перетворення винятків у HTTP-відповіді
  1. Простий приклад middleware
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class AuthMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // перевірка auth, потім продовжуємо
        return $handler->handle($request);
    }
}
  1. Чому PSR-15 важливий
  • Робить middleware перевикористовуваними між фреймворками/екосистемами.
  • Стандартизує точки розширення життєвого циклу запиту.
  • Заохочує чисте розділення наскрізних аспектів (cross-cutting concerns).

PSR-15 надає контракт інтероперабельності для middleware-базованих HTTP-пайплайнів у сучасних PHP-застосунках.

25. Що таке PSR-18 (HTTP-клієнт)?

PHP

PSR-18 — це стандартний інтерфейс для HTTP-клієнтів у PHP. Він визначає, як код застосунку надсилає вихідні HTTP-запити у спосіб, незалежний від конкретної реалізації.

  1. Базовий контракт PSR-18
  • Основний інтерфейс: Psr\Http\Client\ClientInterface
  • Основний метод: sendRequest(RequestInterface $request): ResponseInterface
  • Працює з об’єктами запиту/відповіді PSR-7.
  1. Яку проблему це вирішує
  • Розв’язує бізнес-логіку від конкретних HTTP client бібліотек.
  • Робить інтеграції портативними й простішими для тестування.
  • Дозволяє замінювати реалізації клієнта без переписування сервісного коду.
  1. Базове використання
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;

final class GitHubApi
{
    public function __construct(
        private ClientInterface $client,
        private RequestFactoryInterface $requests,
    ) {}

    public function getUser(string $login): string
    {
        $request = $this->requests->createRequest('GET', "https://api.github.com/users/{$login}");
        $response = $this->client->sendRequest($request);

        return (string) $response->getBody();
    }
}
  1. Винятки

PSR-18 визначає стандартні exception-інтерфейси для збоїв клієнта (помилки запиту, мережеві/транспортні помилки), що дає консистентну обробку помилок між різними реалізаціями.

  1. Найкращі практики
  • Type-hint ClientInterface у сервісах.
  • Будуйте запити через PSR-17 factories.
  • Налаштовуйте timeouts/retries/circuit-breakers в infrastructure-шарі.
  • Мокуйте інтерфейс клієнта в тестах для детермінованої поведінки.

PSR-18 стандартизує вихідну HTTP-комунікацію та є важливою частиною інтероперабельного, підтримуваного інтеграційного коду в сучасних PHP-застосунках.

26. Що таке dependency injection та inversion of control?

PHP

Dependency Injection (DI) та Inversion of Control (IoC) — це архітектурні принципи для побудови слабо зв’язаного і тестованого коду.

  1. Inversion of Control (IoC)

IoC означає, що клас не створює і не контролює свої залежності напряму; цей контроль виноситься назовні (у framework/container/bootstrap-шар).

  1. Dependency Injection (DI)

DI — це конкретний спосіб реалізувати IoC: залежності надаються (інжектяться) ззовні, а не створюються через new всередині класу.

  1. Чому це важливо
  • Зменшує зв’язність між компонентами.
  • Покращує тестованість (простий mocking/stubbing).
  • Полегшує розширення та рефакторинг коду.
  • Підтримує чисті архітектурні межі.
  1. Без DI (tightly coupled)
final class OrderService
{
    private Mailer $mailer;

    public function __construct()
    {
        $this->mailer = new Mailer();
    }
}
  1. З DI (loosely coupled)
interface MailerInterface
{
    public function send(string $to, string $message): void;
}

final class OrderService
{
    public function __construct(private MailerInterface $mailer) {}
}
  1. Поширені стилі DI
  • Constructor injection (рекомендовано).
  • Method injection.
  • Setter/property injection (менш бажано для обов’язкових залежностей).
  1. Зв’язок із контейнерами

DI-контейнер автоматизує створення об’єктів і wiring залежностей, але DI — це дизайн-принцип, незалежний від конкретного контейнера.

DI + IoC — фундамент сучасних PHP-фреймворків і ключ до підтримуваних, масштабованих кодових баз.

27. Що таке service containers і як вони працюють?

PHP

Service container (DI container) — це компонент, який керує створенням об’єктів, wiring залежностей і життєвим циклом у застосунку.

  1. Що робить контейнер
  • Зберігає service definitions/bindings.
  • Автоматично резолвить залежності (часто через reflection і type hints).
  • Будує графи об’єктів (сервіс + усі вкладені залежності).
  • Керує життєвими циклами (singleton/scoped/transient залежно від фреймворку).
  1. Чому це корисно
  • Централізує конфігурацію залежностей.
  • Прибирає повторюваний ручний wiring через new ....
  • Спрощує заміну реалізацій (interface -> concrete class).
  • Підвищує підтримуваність у великих застосунках.
  1. Типовий потік
  • Ви реєструєте bindings: LoggerInterface -> MonologLogger
  • Ви просите в контейнера сервіс: OrderService
  • Контейнер будує OrderService, рекурсивно резолвлячи потрібні аргументи конструктора.
  1. Концептуальний приклад
$container->set(LoggerInterface::class, MonologLogger::class);
$container->set(OrderService::class, fn($c) => new OrderService($c->get(LoggerInterface::class)));

$service = $container->get(OrderService::class);
  1. Концепції життєвого циклу сервісів
  • Singleton/shared: один екземпляр перевикористовується.
  • Transient/factory: новий екземпляр на кожний resolution.
  • Scoped/request: один екземпляр на scope запиту (залежить від фреймворку).
  1. Найкращі практики
  • Де можливо, реєструйте абстракції (інтерфейси), а не конкретні класи.
  • Тримайте бізнес/domain код container-agnostic.
  • За замовчуванням використовуйте constructor injection.
  • Уникайте прямого виклику контейнера глибоко в domain-логіці (Service Locator anti-pattern).

Service containers — це інфраструктурний інструмент, який автоматизує керування залежностями і підтримує модульність та композиційність сучасних PHP-застосунків.

28. Що таке middleware і request lifecycle у фреймворках?

PHP

У сучасних PHP-фреймворках middleware — це шари, які обробляють HTTP-запити та відповіді навколо основної логіки route/controller. Request lifecycle — це повний шлях від вхідного запиту до фінальної відповіді.

  1. Що таке middleware
  • Компонент pipeline, який може: переглядати/модифікувати запит, зупинити обробку власною відповіддю або передати керування наступному шару.
  • У сучасних екосистемах часто реалізується у стилі контрактів PSR-15.
  1. Типові обов’язки middleware
  • Authentication and authorization
  • CORS
  • Rate limiting
  • Нормалізація/валідація вводу
  • Logging, tracing, metrics
  • Обробка винятків і формування відповіді
  1. Типовий request lifecycle

  2. HTTP-запит потрапляє на вебсервер (Nginx/Apache) і PHP runtime.

  3. Framework bootstrap завантажує конфігурацію, сервіси та маршрути.

  4. Стартує глобальний middleware pipeline.

  5. Маршрут матчується, і запускається route-specific middleware.

  6. Controller/handler виконує бізнес-логіку.

  7. Відповідь повертається через middleware-стек (post-processing).

  8. Фінальна відповідь надсилається клієнту.

  9. Чому ця модель корисна

  • Відділяє наскрізні аспекти від контролерів.
  • Дозволяє route handlers фокусуватися на бізнес-логіці.
  • Робить поведінку композиційною та перевикористовуваною.
  • Дає консистентні точки розширення для платформених політик.
  1. Практичні рекомендації
  • Тримайте middleware сфокусованим на одній відповідальності.
  • Осмислено впорядковуйте middleware (наприклад, error handling — зовнішнім шаром).
  • Уникайте важкої бізнес-логіки в middleware.
  • По можливості використовуйте stateless middleware.

Middleware + request lifecycle — ключові архітектурні концепції чистої та передбачуваної HTTP-обробки у PHP-фреймворках.

29. Що таке MVC і як його реалізують у PHP-фреймворках?

PHP

MVC (Model-View-Controller) — це архітектурний патерн, який розділяє відповідальності застосунку на шар даних/бізнес-логіки, шар представлення і шар оркестрації запиту.

  1. Компоненти MVC
  • Model - доменна/дані-логіка, правила та взаємодія з persistence.
  • View - шар представлення (templates/HTML/JSON formatting).
  • Controller - приймає запит, координує use cases, повертає відповідь.
  1. Як це працює у PHP-фреймворках

Типовий flow:

  1. Router матчує URL до дії контролера.

  2. Controller валідує ввід і викликає domain/service/model шар.

  3. Model/service отримує або змінює дані.

  4. Controller передає результат у view/template або повертає API-відповідь.

  5. Framework емітить фінальну HTTP-відповідь.

  6. Приклад відповідальностей

  • Controller: UserController@show($id)
  • Model/Service: отримати користувача, застосувати бізнес-правила
  • View: рендер user/show.blade.php (або JSON resource)
  1. Чому MVC корисний
  • Чіткий поділ відповідальностей.
  • Простіша підтримка і тестування.
  • Краща командна співпраця (frontend/backend-зони відповідальності розділені).
  • Передбачувана структура проєкту.
  1. Поширені помилки
  • Fat controllers із бізнес-логікою.
  • Fat models, що змішують забагато відповідальностей.
  • Тісне зв’язування контролерів із деталями persistence.
  1. Сучасна практика в PHP

Багато проєктів використовують MVC як базу, але виносять бізнес-логіку в service/use-case шари, залишаючи контролери thin, а views простими.

MVC залишається практичною основою у фреймворках на кшталт Laravel та застосунках у стилі Symfony, особливо в поєднанні з принципами чистого шарування.

30. Що таке hexagonal / clean architecture у PHP?

PHP

Hexagonal (Ports and Adapters) і Clean Architecture — це підходи, які тримають бізнес-логіку незалежною від фреймворків, баз даних і зовнішніх сервісів.

  1. Базова ідея
  • Бізнес-правила розміщуються в центрі (domain/use cases).
  • Зовнішні системи розглядаються як замінні адаптери.
  • Залежності спрямовані всередину: інфраструктура залежить від домену, а не навпаки.
  1. Основні будівельні блоки
  • Domain layer: сутності, value objects, доменні правила.
  • Application/use-case layer: оркеструє бізнес-сценарії.
  • Ports (interfaces): контракти для потрібних можливостей (repositories, gateways, buses).
  • Adapters: конкретні реалізації (MySQL repository, HTTP client, queue publisher).
  • Delivery layer: HTTP controllers/CLI/consumers, які викликають use cases.
  1. Чому це важливо
  • Фреймворк або БД можна змінити з мінімальним впливом на ядро бізнес-логіки.
  • Use cases простіше тестувати в ізоляції.
  • Чіткі межі зменшують зв’язність і довгострокові ризики підтримки.
  1. PHP-орієнтований приклад
  • CreateOrderUseCase залежить від OrderRepositoryInterface і PaymentGatewayInterface.
  • Controller у Laravel/Symfony викликає use case.
  • MySQL repository і Stripe adapter реалізують інтерфейси в інфраструктурному шарі.
  1. Структура папок (концептуально)
  • src/Domain/...
  • src/Application/...
  • src/Infrastructure/...
  • src/Interface/Http/... (або Presentation/...)
  1. Практичні рекомендації
  • Тримайте framework-класи поза доменним шаром.
  • Виражайте межі через інтерфейси на стику application/domain.
  • Мапте framework request/response DTO на межах, а не всередині домену.
  • Починайте просто і додавайте шари там, де це виправдано складністю.

Hexagonal/Clean architecture допомагає PHP-системам залишатися гнучкими, тестованими і стабільними в міру еволюції продукту та інфраструктури.

31. Що таке патерн Repository?

PHP

Repository — це патерн, що абстрагує доступ до даних за доменно-орієнтованим інтерфейсом, щоб бізнес-логіка працювала з колекціями/агрегатами, а не напряму з деталями SQL/ORM.

  1. Базова ідея
  • Domain/application шари залежать від інтерфейсів репозиторіїв.
  • Infrastructure шар надає конкретні реалізації (PDO/Doctrine/Eloquent/API).
  • Питання persistence залишаються поза use-case логікою.
  1. Що зазвичай надає Repository
  • Отримання сутностей/агрегатів (findById, findByCriteria).
  • Збереження змін (save, remove).
  • Query-операції, виражені в доменних термінах.
  1. Приклад інтерфейсу
interface OrderRepositoryInterface
{
    public function getById(string $id): ?Order;
    public function save(Order $order): void;
}
  1. Чому це корисно
  • Розв’язує бізнес-логіку від технології зберігання.
  • Покращує тестованість (прості in-memory/mock реалізації).
  • Підтримує архітектурні межі (hexagonal/clean).
  • Робить міграції/рефакторинг безпечнішими при зміні persistence.
  1. Поширені помилки
  • Перетворення repository на generic CRUD-звалище без доменного наміру.
  • Непотрібне дублювання всіх ORM-методів один-в-один.
  • Розміщення бізнес-логіки в реалізації repository.
  1. Практичні рекомендації
  • Тримайте інтерфейси repository на межі domain/application.
  • Експонуйте методи, релевантні use cases, а не внутрішнім деталям БД.
  • Для складної фільтрації за потреби використовуйте specifications/query objects.
  • Доручайте repository persistence, а оркестрацію залишайте сервісам/use cases.

Патерн Repository найцінніший у середніх/великих PHP-системах, де довговічність доменної логіки важливіша за короткострокову швидкість CRUD.

32. Що таке DTO і Value Objects?

PHP

DTO і Value Objects — різні патерни, які часто застосовуються разом у сучасній PHP-архітектурі.

  1. DTO (Data Transfer Object)
  • Простий об’єкт для передавання структурованих даних між шарами/процесами.
  • Зазвичай містить поля та мінімум (або взагалі не містить) бізнес-логіки.
  • Допомагає уникати передачі сирих масивів через межі шарів.
final class CreateUserDto
{
    public function __construct(
        public string $email,
        public string $name,
    ) {}
}
  1. Value Object (VO)
  • Доменний об’єкт, який визначається значенням, а не ідентичністю.
  • Зазвичай immutable і self-validating.
  • Інкапсулює доменні правила для конкретної концепції (Email, Money, Currency тощо).
final class Email
{
    public function __construct(public readonly string $value)
    {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Invalid email');
        }
    }
}
  1. Ключові відмінності
  • Призначення: DTO транспортує дані; VO моделює доменний зміст.
  • Логіка: DTO мінімальна; VO може забезпечувати інваріанти.
  • Ідентичність: DTO часто другорядна; VO порівнюється за значенням.
  • Мутабельність: DTO може бути mutable/immutable; VO загалом має бути immutable.
  1. Коли використовувати кожен
  • Використовуйте DTO на межах (HTTP request/response, messaging, input/output application layer).
  • Використовуйте Value Objects всередині доменної моделі для безпечного вираження валідованих концепцій.

DTO покращують ясність потоку даних, а Value Objects підвищують коректність домену та запобігають невалідним станам.

33. Що таке OOP у PHP?

PHP

OOP (Object-Oriented Programming) у PHP — це парадигма програмування, де код організовується навколо об’єктів, які поєднують дані (стан) і поведінку (методи).

  1. Базові концепції OOP
  • Class: шаблон, що визначає властивості та методи.
  • Object: екземпляр класу.
  • Encapsulation: контроль доступу до внутрішніх деталей (public/protected/private).
  • Inheritance: дочірні класи перевикористовують/розширюють поведінку батьківських.
  • Polymorphism: спільні інтерфейси з взаємозамінними реалізаціями.
  • Abstraction: відкривати суттєві контракти, приховувати деталі реалізації.
  1. Чому OOP використовується в PHP
  • Чітко моделює доменні концепції.
  • Заохочує модульний, перевикористовуваний код.
  • Покращує підтримуваність у середніх/великих кодових базах.
  • Природно поєднується з DI, інтерфейсами та архітектурою фреймворків.
  1. Базовий приклад
interface NotifierInterface
{
    public function send(string $message): void;
}

final class EmailNotifier implements NotifierInterface
{
    public function send(string $message): void
    {
        // надсилання email
    }
}

final class AlertService
{
    public function __construct(private NotifierInterface $notifier) {}

    public function alert(string $message): void
    {
        $this->notifier->send($message);
    }
}
  1. Сучасні OOP-можливості PHP
  • Typed properties і strict types
  • Interfaces та abstract classes
  • Traits для горизонтального перевикористання коду
  • Attributes, enums, readonly properties/classes
  • Constructor property promotion
  1. Найкращі практики
  • За можливості віддавайте перевагу композиції над наслідуванням.
  • Пишіть код під інтерфейси, а не під конкретні класи.
  • Тримайте класи сфокусованими (single responsibility).
  • Уникайте “god objects” із занадто великою кількістю обов’язків.

OOP у PHP — основа для більшості сучасних фреймворків і проєктування domain-driven застосунків.

34. Яка різниця між interface та abstract class?

PHP

І interfaces, і abstract classes задають контракти, але служать різним цілям проєктування.

  1. Interface
  • Визначає лише сигнатури методів (контракт) і константи.
  • Не має стану екземпляра (без властивостей із runtime-станом).
  • Клас може імплементувати кілька інтерфейсів.
  • Фокус: контракт можливостей і поліморфізм.
interface PaymentGatewayInterface
{
    public function charge(int $amount): bool;
}
  1. Abstract class
  • Може містити і абстрактні методи, і вже реалізовані методи.
  • Може мати спільний стан/поведінку (властивості, protected-хелпери, логіку конструктора).
  • Клас може наслідувати лише один abstract/base class.
  • Фокус: часткова реалізація + спільна базова поведінка.
abstract class BaseGateway
{
    public function __construct(protected string $apiKey) {}

    abstract public function charge(int $amount): bool;

    protected function log(string $message): void
    {
        // shared logic
    }
}
  1. Ключові відмінності
  • Множинне наслідування типу: багато interfaces, але лише один батьківський class.
  • Спільний код: в abstract class — так, в interface — ні.
  • Зв’язність: interface зазвичай слабше зв’язує; abstract class додає зв’язування через наслідування.
  1. Коли обирати
  • Використовуйте interface, коли потрібні взаємозамінні реалізації та чіткі контракти.
  • Використовуйте abstract class, коли реалізації мають змістовну спільну базову логіку/стан.
  1. Практичне правило

Для публічних архітектурних меж віддавайте перевагу interfaces; abstract classes використовуйте як внутрішній інструмент перевикористання, коли наслідування справді виправдане.

Interface = «що це вміє», abstract class = «що тут частково вже реалізовано».

35. Що таке traits і коли їх варто використовувати?

PHP

Traits у PHP — це механізм горизонтального перевикористання коду: вони дозволяють класам перевикористовувати методи (і пов’язані члени) без наслідування.

  1. Що таке trait
  • Перевикористовувана одиниця коду, оголошена через trait.
  • Підключається в класи через use.
  • Допомагає ділитися поведінкою між непов’язаними ієрархіями класів.
trait Timestampable
{
    public function touch(): void
    {
        $this->updatedAt = new DateTimeImmutable();
    }
}

final class Post
{
    use Timestampable;
}
  1. Коли traits корисні
  • Спільна наскрізна поведінка (logging helpers, timestamps, невеликі утилітарні поведінки).
  • Перевикористання між класами, які не можуть мати спільного батьківського класу.
  • Зменшення дублювання, коли композиція була б занадто багатослівною для маленьких блоків поведінки.
  1. Розв’язання конфліктів trait-ів

Якщо два traits визначають однаковий метод, PHP надає механізми розв’язання конфлікту:

  • insteadof — щоб обрати одну реалізацію.
  • as — щоб задати псевдонім/перейменувати метод.
  1. Обмеження і ризики
  • Traits можуть приховувати зв’язність і розмивати відповідальності класу при надмірному використанні.
  • Великі “god traits” складно тестувати та підтримувати.
  • Це включення коду, а не справжні поліморфні контракти.
  1. Найкращі практики
  • Тримайте traits малими й сфокусованими.
  • Використовуйте traits для перевикористання поведінки, а не для доменного моделювання.
  • Для ключових архітектурних меж віддавайте перевагу interfaces + composition.
  • Уникайте зберігання складного mutable shared state всередині traits.

Traits — практичний інструмент PHP для точкового перевикористання, але найкраще працюють як легке доповнення до хорошого об’єктного дизайну, а не як його заміна.

36. Що таке magic methods і коли вони викликаються?

PHP

Magic methods — це спеціальні методи PHP (з префіксом __), які рушій автоматично викликає під час певних подій життєвого циклу об’єкта або взаємодії з ним.

  1. Magic methods життєвого циклу об’єкта
  • __construct() - викликається при створенні об’єкта.
  • __destruct() - викликається при знищенні об’єкта (або в кінці скрипта).
  • __clone() - викликається після клонування об’єкта.
  1. Magic methods доступу до властивостей
  • __get($name) - читання недоступної/невизначеної властивості.
  • __set($name, $value) - запис у недоступну/невизначену властивість.
  • __isset($name) - isset()/empty() для недоступної/невизначеної властивості.
  • __unset($name) - unset() для недоступної/невизначеної властивості.
  1. Перехоплення викликів методів
  • __call($name, $arguments) - виклик недоступного/невизначеного instance-методу.
  • __callStatic($name, $arguments) - виклик недоступного/невизначеного static-методу.
  1. Рядок/виклик/серіалізація
  • __toString() - коли об’єкт використовується як рядок.
  • __invoke(...$args) - коли об’єкт викликається як функція.
  • __serialize() / __unserialize() - кастомна логіка серіалізації.
  1. Хелпери експорту стану/дебагу
  • __set_state(array $properties) - викликається під час відновлення через var_export().
  • __debugInfo() - кастомний вивід для var_dump().
  1. Простий приклад
final class User
{
    private array $data = [];

    public function __get(string $name): mixed
    {
        return $this->data[$name] ?? null;
    }

    public function __set(string $name, mixed $value): void
    {
        $this->data[$name] = $value;
    }
}
  1. Найкращі практики
  • Використовуйте magic methods усвідомлено, а не як архітектуру за замовчуванням.
  • Робіть поведінку явною та передбачуваною.
  • Не приховуйте помилки надто permissive-реалізаціями __get/__set.
  • За можливості віддавайте перевагу typed properties/methods.

Magic methods — потужні точки розширення, але їх слід застосовувати обережно, бо при надмірному використанні вони зменшують прозорість коду.

37. Що таке late static binding?

PHP

Late Static Binding (LSB) у PHP дозволяє резолвити static methods/properties на основі класу, який викликається в runtime, а не лише класу, де метод був оголошений.

  1. self:: vs static::
  • self:: прив’язаний до класу, де метод оголошено (early binding).
  • static:: резолвиться до викликаного класу в runtime (late static binding).
  1. Чому це важливо
  • Дає поліморфну поведінку в static-контексті.
  • Корисно в ієрархіях наслідування, де дочірні класи мають контролювати повернений клас/значення.
  • Часто використовується у factory-патернах і Active Record-подібних API.
  1. Приклад
class BaseModel
{
    public static function table(): string
    {
        return static::TABLE; // late static binding
    }
}

class User extends BaseModel
{
    protected const TABLE = 'users';
}

class Order extends BaseModel
{
    protected const TABLE = 'orders';
}

echo User::table();  // users
echo Order::table(); // orders

Якби використовувався self::TABLE, поведінка була б жорстко зафіксована контекстом базового оголошення.

  1. Пов’язане ключове слово
  • Тип повернення static (public static function make(): static) також використовує late static семантику і повертає тип викликаного класу.
  1. Практичні рекомендації
  • Використовуйте static::, коли підкласи мають кастомізувати static-поведінку.
  • Використовуйте self::, коли поведінка має бути свідомо зафіксована на рівні базової реалізації.

Late static binding — важлива OOP-можливість для розширюваних ієрархій класів у PHP.

38. Як об’єкти обробляються в пам’яті у PHP?

PHP

У PHP об’єкти керуються Zend Engine як структури, розміщені в heap-пам’яті та доступні через object handles, з автоматичним керуванням пам’яттю через reference counting і garbage collection.

  1. Модель зберігання об’єктів
  • Екземпляри об’єктів алокуються у пам’яті, якою керує рушій (heap).
  • Змінні містять посилання (handles) на об’єктні записи, а не повні копії об’єкта.
  • Присвоєння однієї об’єктної змінної іншій копіює handle, а не стан об’єкта.
$a = new stdClass();
$a->x = 1;

$b = $a;      // те саме посилання на об’єкт
$b->x = 2;

echo $a->x;   // 2
  1. Підрахунок посилань (reference counting)
  • Рушій відстежує, скільки zval посилаються на значення/об’єкт.
  • Коли лічильник падає до нуля, пам’ять може бути звільнена.
  • Для об’єктів це зазвичай означає виклик деструктора та очищення об’єкта.
  1. Garbage collector (GC)
  • Лише reference counting не може зібрати циклічні посилання.
  • GC у PHP виявляє і прибирає циклічне «сміття» (наприклад, графи об’єктів, що посилаються один на одного).
  1. Поведінка клонування
  • clone створює новий екземпляр об’єкта (окрема ідентичність).
  • __clone() дозволяє кастомізувати логіку стану після клонування.
  1. Нюанс pass-by-reference
  • Передавання об’єктів у функції фактично відбувається через handle (зміни об’єкта видно зовні).
  • Зазвичай & не потрібен, щоб мутувати стан об’єкта через межі функції.
  1. Наслідки для продуктивності/пам’яті
  • Великі графи об’єктів підвищують тиск на пам’ять.
  • Довгоживучі посилання (static caches, closures, global containers) можуть затримувати очищення.
  • За циклічними посиланнями у long-running workers треба стежити, щоб уникати зростання, схожого на витоки.
  1. Практичні рекомендації
  • Тримайте графи об’єктів усвідомленими та обмеженими.
  • У long-running процесах за потреби явно unset великих тимчасових структур.
  • Використовуйте профайлінг-інструменти для пошуку memory hotspots.
  • Обережно з static singletons/global state у workers/daemons.

Обробка об’єктів у пам’яті PHP ефективна для типових request lifecycle, але long-running процеси потребують дисципліни в роботі з пам’яттю.

39. Що таке PDO і чому йому віддають перевагу?

PHP

PDO (PHP Data Objects) — це шар абстракції доступу до баз даних у PHP, який надає консистентний API для роботи з різними СУБД.

  1. Що надає PDO
  • Уніфікований інтерфейс для DB-операцій (MySQL, PostgreSQL, SQLite тощо).
  • Prepared statements і parameter binding.
  • Підтримку транзакцій.
  • Налаштовувані fetch modes і обробку помилок.
  1. Чому PDO є preferred
  • Портативність: однаковий стиль коду між різними БД.
  • Безпека: prepared statements знижують ризик SQL injection.
  • Підтримуваність: чистіший, стандартизований код доступу до БД.
  • Контроль: явна поведінка транзакцій/помилок.
  1. Базовий приклад
$pdo = new PDO(
    'mysql:host=localhost;dbname=app;charset=utf8mb4',
    'user',
    'pass',
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]
);

$stmt = $pdo->prepare('SELECT id, email FROM users WHERE id = :id');
$stmt->execute(['id' => 42]);
$user = $stmt->fetch();
  1. PDO vs прямі driver-specific API
  • PDO дає спільну абстракцію та чистіші архітектурні межі.
  • Driver-specific API можуть відкривати нішеві можливості, але зменшують портативність.
  1. Найкращі практики
  • Завжди вмикайте режим винятків (PDO::ERRMODE_EXCEPTION).
  • Використовуйте prepared statements для всього зовнішнього вводу.
  • Явно задавайте charset у DSN (наприклад, utf8mb4).
  • Явно керуйте транзакціями для багатокрокових записів.

PDO є стандартним вибором у сучасному PHP, бо поєднує безпеку, портативність і зрозумілі патерни доступу до БД.

40. Що таке prepared statements і parameter binding?

PHP

Prepared statements — це SQL-запити, скомпільовані як шаблони з плейсхолдерами, де значення передаються окремо через parameter binding.

  1. Як це працює
  • Крок 1: підготуйте SQL із плейсхолдерами (:email, ?).
  • Крок 2: окремо прив’яжіть/виконайте значення.
  • База даних трактує прив’язані значення строго як дані, а не як SQL-синтаксис.
  1. Чому це важливо
  • Основний захист від SQL injection.
  • Чистіший і безпечніший код запитів.
  • Краще опрацювання типів і escaping на рівні драйвера.
  • Може покращувати продуктивність для повторного виконання запитів (залежно від БД/драйвера).
  1. Приклад із named placeholders (PDO)
$stmt = $pdo->prepare(
    'SELECT id, email FROM users WHERE email = :email AND status = :status'
);

$stmt->execute([
    'email' => $email,
    'status' => $status,
]);
  1. Приклад із positional placeholders
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
  1. Binding з явними типами
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
  1. Важливий нюанс
  • Prepared statements захищають значення, але не SQL-ідентифікатори (імена таблиць/колонок).
  • Динамічні ідентифікатори потрібно контролювати через строгі allowlist.
  1. Найкращі практики
  • Використовуйте prepared statements для кожного запиту, що містить зовнішній ввід.
  • Уникайте конкатенації рядків для SQL-умов.
  • Тримайте SQL-шаблони читабельними та явними.
  • Поєднуйте з least-privileged DB users і коректними межами транзакцій.

Prepared statements + parameter binding — стандартний, обов’язковий baseline для безпечного доступу до БД у PHP.

41. Як працюють транзакції у PHP?

PHP

Транзакції в PHP (через PDO/MySQLi) об’єднують кілька операцій із базою в одну атомарну одиницю: або всі зміни комітяться, або всі відкочуються.

  1. Базові операції транзакції
  • beginTransaction() - стартує транзакцію.
  • commit() - незворотно зберігає всі зміни.
  • rollBack() - скасовує всі незафіксовані зміни.
  1. Навіщо потрібні транзакції
  • Забезпечують консистентність даних для багатокрокових записів.
  • Запобігають частковим оновленням у разі помилки.
  • Зберігають бізнес-інваріанти (наприклад, списання й зарахування мають успішно виконатися обидва).
  1. Базовий приклад PDO
try {
    $pdo->beginTransaction();

    $stmt1 = $pdo->prepare('UPDATE accounts SET balance = balance - :amount WHERE id = :from');
    $stmt1->execute(['amount' => 100, 'from' => 1]);

    $stmt2 = $pdo->prepare('UPDATE accounts SET balance = balance + :amount WHERE id = :to');
    $stmt2->execute(['amount' => 100, 'to' => 2]);

    $pdo->commit();
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }
    throw $e;
}
  1. Ізоляція і конкурентність
  • Рівень ізоляції БД контролює видимість/блокування між конкурентними транзакціями.
  • Типові аномалії: dirty reads, non-repeatable reads, phantom reads.
  • Рівень ізоляції обирають за компромісом консистентність/продуктивність.
  1. Практичні підводні камені
  • Довгі транзакції тримають блокування і погіршують конкурентність.
  • Зовнішні API/мережеві виклики всередині DB-транзакції збільшують вікно збоїв.
  • Відсутність rollback при винятках може лишити workflow неконсистентним.
  1. Найкращі практики
  • Тримайте транзакції якомога коротшими.
  • Включайте лише ті DB-операції, які мають бути атомарними.
  • Використовуйте явну обробку помилок і гарантії rollback.
  • Проєктуйте retry-логіку для deadlocks/serialization conflicts за потреби.

Транзакції — базовий механізм надійності для фінансових, складських та інших integrity-critical workflow у PHP-системах.

42. Що таке ORM (Eloquent / Doctrine) і які компроміси?

PHP

ORM (Object-Relational Mapping) — це підхід, який мапить таблиці/рядки БД на PHP-об’єкти, дозволяючи в більшості прикладного коду працювати з доменними сутностями замість сирого SQL.

  1. Що дає ORM
  • Entity/model класи, замаплені на схеми БД.
  • Query API/builders замість ручного SQL для типових операцій.
  • Роботу зі зв’язками (hasMany, belongsTo тощо).
  • Unit-of-work/change tracking (особливо в Doctrine).
  • Migrations та екосистемні інструменти в багатьох фреймворках.
  1. Поширені ORM у PHP
  • Eloquent (Laravel): стиль Active Record, швидка продуктивність розробки, виразний синтаксис.
  • Doctrine ORM: стиль Data Mapper, багате доменне моделювання, сильніший поділ відповідальностей.
  1. Переваги
  • Швидша розробка CRUD-насичених фіч.
  • Чистіший і читабельніший persistence-код у типових сценаріях.
  • Простіший обхід зв’язків і model-centric workflow.
  • Конвенції та інтеграції з екосистемою.
  1. Компроміси / недоліки
  • Overhead абстракції та потенційна втрата продуктивності.
  • Приховані/неявні запити (проблема N+1).
  • Для складного SQL/звітності часто все одно потрібен ручний SQL.
  • ORM-специфічні патерни можуть підвищувати складність входу і lock-in.
  1. Коли ORM працює найкраще
  • Бізнес-застосунки з частими операціями життєвого циклу сутностей.
  • Команди, які цінують швидкість розробки та підтримуваний model-centric код.
  1. Коли краще raw SQL/query builders
  • Performance-critical hot paths.
  • Складні аналітичні/звітні запити.
  • Vendor-specific можливості БД і тонкий контроль SQL.
  1. Практична стратегія
  • За замовчуванням використовуйте ORM для типових доменних операцій.
  • Профілюйте й оптимізуйте bottlenecks.
  • Поєднуйте ORM з оптимізованим SQL там, де потрібно (hybrid approach).
  • Явно керуйте eager/lazy loading, щоб уникати «вибуху» запитів.

ORM — потужний множник продуктивності в PHP, але якісна інженерія вимагає розуміння, де абстракція допомагає, а де кращий нижчорівневий контроль SQL.

43. Що таке connection pooling і чому це важливо?

PHP

Connection pooling — це техніка, за якої з’єднання з БД перевикористовуються з керованого пулу, а не створюються і закриваються для кожної окремої операції.

  1. Чому з’єднання дорогі
  • Відкриття DB-з’єднання включає мережевий handshake, автентифікацію та алокацію ресурсів на сервері.
  • Часті перепідключення збільшують latency і CPU-навантаження як на застосунок, так і на БД.
  1. Що робить pooling
  • Підтримує перевикористовуваний набір відкритих з’єднань.
  • Призначає наявне з’єднання для вхідної роботи.
  • Повертає його в пул після використання для наступних запитів/джобів.
  1. Чому це важливо
  • Зменшує latency запитів.
  • Підвищує throughput під навантаженням.
  • Зменшує churn і overhead DB-з’єднань.
  • Стабілізує поведінку high-concurrency систем.
  1. Нюанс у контексті PHP
  • У класичній PHP-FPM request-моделі кожен worker-процес має ізольований життєвий цикл, тому pooling менш прямолінійний, ніж у long-lived runtime.
  • Типові практичні підходи: persistent connections (PDO::ATTR_PERSISTENT з обережністю), зовнішні poolers/proxies (наприклад, PgBouncer для PostgreSQL), long-running workers (RoadRunner/Swoole/queue consumers), де перевикористання пряміше.
  1. Компроміси / ризики
  • Stale/broken connections потрібно виявляти та перезапускати.
  • Невдалий розмір пулу може викликати contention або перевантаження БД.
  • Persistent connections можуть тримати серверні ресурси довше, ніж очікується.
  1. Найкращі практики
  • Встановлюйте адекватні pool/connection limits відповідно до ємності БД.
  • Використовуйте health checks/timeouts для з’єднань.
  • Моніторте кількість з’єднань, час очікування і error rates.
  • Тримайте запити ефективними; pooling не виправляє повільний SQL.

Connection pooling — ключова техніка масштабування для PHP-систем, інтенсивних до БД, особливо під сталим конкурентним трафіком.

44. Як структурувати масштабований PHP-застосунок?

PHP

Масштабований PHP-застосунок будується навколо чітких меж, передбачуваної архітектури й операційної готовності до зростання трафіку, команди та складності фіч.

  1. Використовуйте шарові/модульні межі
  • Розділяйте за відповідальностями та бізнес-доменами, а не лише за технічними папками.
  • Типові шари: Domain, Application/UseCases, Infrastructure, Interface/HTTP.
  1. Тримайте бізнес-логіку framework-agnostic
  • Розміщуйте core-правила у domain/use-case шарі.
  • Тримайте контролери thin.
  • Залежте від інтерфейсів; DB/framework adapters лишайте в infrastructure-шарі.
  1. Проєктуйте під stateless horizontal scale
  • Уникайте локального mutable state в інстансах застосунку.
  • Зберігайте спільний стан у зовнішніх системах: DB, Redis, object storage, queues.
  • Робіть sessions/cache готовими до multi-node deployment.
  1. Стратегія даних і persistence
  • Використовуйте repositories/services як межі persistence.
  • Рано застосовуйте індексацію й оптимізацію запитів.
  • Додавайте кешування (application/query/HTTP), де це виправдано.
  • Використовуйте read/write separation і partitioning лише за реальної потреби.
  1. Async і фонова обробка
  • Виносьте некритичні/повільні задачі в черги (emails, exports, notifications, webhooks).
  • Тримайте request path швидким і детермінованим.
  1. Операційна масштабованість
  • Контейнеризуйте навантаження (Docker/K8s/managed platforms).
  • Використовуйте health checks, structured logging, metrics, tracing.
  • Додавайте rate limiting, timeouts, retries, circuit breakers.
  • Будуйте CI/CD із безпечними rollout/rollback стратегіями.
  1. Масштабованість кодової бази для команди
  • Дотримуйтеся coding standards і static analysis.
  • Підтримуйте модульні межі пакетів.
  • Використовуйте integration і contract tests на критичних шляхах.
  • Документуйте архітектурні рішення (ADRs) та сервісні контракти.
  1. Практичний шлях еволюції
  • Починайте з modular monolith і сильних меж.
  • Виділяйте сервіси лише тоді, коли це чітко виправдано обмеженнями масштабування/команди.

Масштабованість у PHP — передусім дисципліна архітектури й операцій, а не вибір одного конкретного фреймворку.

45. Як обробляти конфігурацію (env variables)?

PHP

У сучасних PHP-застосунках конфігурація має бути винесена з коду та передаватися через environment variables, відповідно до 12-factor принципів.

  1. Базовий принцип
  • Тримайте конфігурацію поза source code.
  • Вважайте environment джерелом deploy-специфічних налаштувань: DB credentials, API URLs, cache hosts, feature flags тощо.
  1. Типовий setup
  • Development: .env файл (завантажується фреймворком/bootstrap).
  • Production: реальні environment variables від платформи/orchestrator (не .env у репозиторії).
  1. Як споживаються значення
  • Читайте env один раз у config bootstrap.
  • Мапте значення у типізовану config-структуру/об’єкт.
  • Інжектіть конфігурацію в сервіси через DI.
  1. Хороші практики
  • Розділяйте конфігурацію за середовищами (dev, staging, prod) через env-значення.
  • Задавайте defaults лише для нечутливих значень локальної розробки.
  • Валідуйте обов’язкову конфігурацію на старті й fail fast, якщо бракує/некоректна.
  • Тримайте config-ключі консистентними й задокументованими.
  1. Чого не робити
  • Не хардкодьте credentials у коді.
  • Не комітьте production secrets у репозиторій.
  • Не викликайте getenv() хаотично в domain-логіці.
  • Не змішуйте бізнес-логіку з логікою завантаження конфігурації.
  1. Практичний патерн

Використовуйте центральні config-файли, що підтягують значення з env, наприклад:

  • config/database.php
  • config/cache.php
  • config/app.php

Потім інжектіть уже резолвлену конфігурацію в залежні сервіси.

  1. Нотатка про безпеку

Environment variables кращі за хардкод секретів, але теж чутливі: обмежуйте доступ, уникайте логування повних значень і комбінуйте з dedicated secret managers для критичних credentials.

Керування конфігурацією через env variables робить PHP-застосунки портативними, безпечними та консистентними між середовищами.

46. Як керувати секретами (Vault, AWS Secrets Manager)?

PHP

Secrets management — це практика безпечного зберігання, ротації та доступу до чутливих значень (API keys, DB passwords, tokens, certificates) поза кодом застосунку.

  1. Чому потрібні спеціалізовані secret managers
  • Запобігають витоку секретів у репозиторій/історію.
  • Централізують контроль доступу й аудит.
  • Дозволяють безпечну ротацію без редеплою коду.
  • Знижують операційний ризик порівняно зі звичайними .env файлами.
  1. Поширені інструменти
  • HashiCorp Vault: dynamic secrets, leases, policy-based доступ, сильні audit-можливості.
  • AWS Secrets Manager: managed secret storage/rotation з інтеграцією IAM і сервісів AWS.
  • (Також часто використовують cloud-native parameter stores або KMS-backed рішення.)
  1. Рекомендований потік роботи з секретами

  2. Встановлюється ідентичність застосунку (IAM role, workload identity, Vault auth method).

  3. Застосунок отримує потрібні секрети на старті (або on demand з кешем).

  4. Секрети тримаються в пам’яті лише настільки, наскільки потрібно.

  5. Події ротації обробляються без хардкоду значень.

  6. Найкращі практики

  • Ніколи не комітьте секрети в git (включно з прикладами файлів із реальними значеннями).
  • Використовуйте least-privilege access policies для кожного сервісу/середовища.
  • Регулярно ротуйте секрети та робіть позапланову ротацію після інцидентів.
  • Логуйте метадані доступу, але ніколи не значення секретів.
  • Розділяйте секрети за середовищами (dev/staging/prod) і scope сервісів.
  • За можливості використовуйте short-lived credentials (dynamic DB creds/tokens).
  1. Патерн інтеграції у PHP
  • Отримуйте секрети в bootstrap/infrastructure шарі.
  • Мапте їх у типізовані config-об’єкти.
  • Інжектіть config/secrets у залежні сервіси через DI.
  • Додавайте fallback і retry-стратегію на випадок недоступності secret manager.
  1. Операційні аспекти
  • Кешуйте секрети з TTL для зменшення latency та API-лімітів.
  • Продумуйте поведінку bootstrap, коли backend секретів тимчасово недоступний.
  • Тестуйте процедуру ротації в staging перед production rollout.

Використання Vault/AWS Secrets Manager переводить роботу із секретами з ad-hoc env variables у контрольований security-процес, придатний для production PHP-систем.

47. Що таке 12-factor app у контексті PHP?

PHP

12-factor app — це набір cloud-native інженерних принципів для побудови портативних, масштабованих і підтримуваних сервісів. У PHP ці принципи допомагають перейти від «server-coupled apps» до сучасних deployable-сервісів.

  1. Codebase
  • Одна кодова база у version control.
  • Багато deploy-оточень (dev/staging/prod) з тієї самої кодової бази.
  1. Dependencies
  • Явно оголошуйте залежності в composer.json.
  • Не покладайтеся на глобально встановлені системні пакети.
  1. Config
  • Зберігайте конфігурацію в environment variables, а не в коді.
  • Тримайте secrets і environment-специфічні значення поза репозиторієм.
  1. Backing services
  • Сприймайте DB, cache, queue, object storage як підключені ресурси.
  • Звертайтесь до них через config/URLs, щоб можна було замінювати по середовищах.
  1. Розділення build, release, run
  • Збирайте артефакт один раз.
  • Промотуйте той самий артефакт між середовищами.
  • Тримайте runtime config окремо від build.
  1. Процеси
  • Запускайте застосунок як stateless-процеси.
  • Зберігайте persistent state у зовнішніх сервісах (DB/Redis/S3 тощо).
  1. Port binding і конкурентність
  • Експонуйте сервіси через HTTP/runtime entrypoints.
  • Масштабуйтеся через реплікацію процесів/контейнерів, а не лише вертикальним тюнінгом.
  1. Disposability і parity
  • Швидкий startup/shutdown для безпечних deploy-ів і autoscaling.
  • Тримайте dev/staging/prod оточення максимально схожими.
  1. Логи й адмін-задачі
  • Сприймайте логи як event streams (stdout/aggregators).
  • Запускайте admin/migration задачі як one-off процеси з тієї ж кодової бази.
  1. PHP-специфічні практичні наслідки
  • Використання Composer + env config + externalized state.
  • Container-friendly runtime (PHP-FPM/CLI workers).
  • Queue workers для фонових задач.
  • CI/CD pipeline з immutable artifacts.

Застосування 12-factor принципів у PHP підвищує надійність деплою, операційну масштабованість і довгострокову підтримуваність.

48. Що таке контейнеризація (Docker) у PHP-застосунках?

PHP

Контейнеризація пакує PHP-застосунок разом із runtime-залежностями в портативний образ, щоб він працював консистентно в локальному середовищі, CI, staging і production.

  1. Що Docker дає PHP-застосункам
  • Відтворюваний runtime (версія PHP, розширення, системні бібліотеки).
  • Паритет середовищ між машинами розробників і production.
  • Простіший деплой, rollback і масштабування.
  • Ізоляцію між сервісами (app, DB, cache, queue, worker).
  1. Типовий контейнеризований PHP-стек
  • PHP-FPM контейнер (runtime застосунку)
  • Nginx/Apache контейнер (web server)
  • Окремі контейнери для DB/Redis/queue workers/cron jobs
  1. Базовий Dockerfile-патерн
FROM php:8.4-fpm-alpine

RUN docker-php-ext-install pdo pdo_mysql opcache
WORKDIR /var/www/html

COPY . .
RUN php -v
  1. Чому це важливо для масштабування
  • Горизонтальне масштабування стає простішим (реплікація контейнерів).
  • Immutable image-based deploys зменшують drift/config mismatch.
  • Природно інтегрується з платформами оркестрації (Kubernetes, ECS, Nomad).
  1. Найкращі практики
  • Використовуйте малі base images і multi-stage builds.
  • Фіксуйте версії image/tag для відтворюваності.
  • Тримайте образи stateless; persistent data зберігайте зовні.
  • Інжектіть config/secrets через env/secret managers, а не «вшивайте» в image.
  • Запускайте health checks і виводьте структуровані логи в stdout/stderr.
  1. Поширені помилки
  • Запуск усього в одному контейнері (web + DB + queue) у production.
  • Запис persistent app data у filesystem контейнера.
  • Великі image з непотрібними build-інструментами в runtime-шарі.

Контейнеризація — базова практика сучасних PHP-операцій, бо стандартизує поведінку runtime і покращує deployability на масштабі.

49. Що таке OPcache і як він покращує продуктивність?

PHP

OPcache — це вбудований PHP bytecode cache, який зберігає скомпільований байткод скриптів у shared memory, тому PHP не потрібно парсити й компілювати ті самі файли на кожному запиті.

  1. Яку проблему вирішує OPcache
  • Без OPcache кожен запит повторює: читання PHP-файлу -> парсинг -> компіляція в opcodes -> виконання.
  • Така повторна компіляція додає CPU-overhead і latency.
  1. Як OPcache покращує продуктивність
  • Скомпільовані opcodes кешуються в пам’яті й перевикористовуються між запитами.
  • Зменшує використання CPU і час обробки запиту.
  • Підвищує throughput під навантаженням.
  • Покращує startup-продуктивність фреймворків із великою кількістю файлів.
  1. Типовий production setup
  • Увімкніть OPcache в PHP runtime (opcache.enable=1).
  • Налаштуйте ліміти пам’яті та кількості файлів: opcache.memory_consumption, opcache.max_accelerated_files.
  • Для immutable release artifacts вимикайте перевірку timestamp: opcache.validate_timestamps=0 (із керованим reset кешу під час деплою).
  1. Корисні налаштування
  • opcache.enable
  • opcache.memory_consumption
  • opcache.max_accelerated_files
  • opcache.interned_strings_buffer
  • opcache.validate_timestamps
  • opcache.revalidate_freq
  1. Deployment-нюанси
  • Коли код змінюється, кешований байткод має оновитися.
  • В immutable/container deploy зазвичай достатньо перезапустити PHP workers.
  • У mutable deploy використовуйте контрольовану стратегію invalidation/restart.
  1. Найкращі практики
  • Завжди використовуйте OPcache у production.
  • Моніторте cache hit rate, використання пам’яті та рестарти.
  • Розмір кешу підбирайте відповідно до росту кодової бази.
  • Поєднуйте OPcache з application/database caching для максимального ефекту.

OPcache — одна з найвпливовіших low-effort оптимізацій продуктивності для production PHP-середовищ.

50. Що таке JIT у PHP і коли він корисний?

PHP

JIT (Just-In-Time compilation) у PHP — це оптимізація рушія, яка компілює вибрані Zend opcodes у native machine code під час runtime.

  1. Що робить JIT
  • Звичайний потік PHP: script -> opcodes -> виконання інтерпретатором.
  • З JIT: «гарячі» ділянки коду можуть компілюватися в native code і виконуватися швидше.
  1. Де JIT може допомогти
  • CPU-інтенсивні навантаження: важка математика, цикли, обробка даних, обчислювальні алгоритми.
  • Long-running CLI workers і спеціалізовані compute-задачі.
  1. Де JIT часто дає мало користі
  • Типові вебзастосунки, де домінує I/O: запити до БД, мережеві виклики, доступ до кешу, рендеринг шаблонів.
  • У багатьох CRUD/API-навантаженнях OPcache й оптимізація запитів важливіші за JIT.
  1. Зв’язок з OPcache
  • JIT побудований поверх інфраструктури OPcache.
  • OPcache зазвичай дає найбільший базовий приріст для більшості застосунків.
  • JIT — додатковий шар оптимізації для CPU-bound коду.
  1. Практичні рекомендації
  • Увімкніть і зробіть benchmark до/після на реальному workload.
  • Не припускайте глобального приросту для всіх типів запитів.
  • Спершу пріоритезуйте усунення bottlenecks: повільний SQL, N+1 queries, надмірні мережеві виклики, неефективне кешування.
  1. Rule of thumb
  • Для класичних web backends вплив JIT зазвичай помірний.
  • Для compute-heavy PHP workload JIT може дати відчутний приріст.

JIT — корисний інструмент оптимізації, але його цінність сильно залежить від профілю навантаження.

51. Що таке lazy loading і де він використовується?

PHP

Lazy loading — це техніка, за якої дані або об’єкти завантажуються лише тоді, коли вони справді потрібні, замість завантаження всього наперед.

  1. Базова ідея
  • Відкласти дорогу ініціалізацію до першого доступу.
  • Зменшити початкове споживання пам’яті та startup time.
  • Платити ціну лише за ті шляхи, які реально використовуються.
  1. Де lazy loading використовується у PHP
  • ORM-зв’язки (Doctrine/Eloquent relation proxies).
  • Ініціалізація сервісів у DI-контейнерах (deferred services).
  • Великі конфігурації/ресурси, що вантажаться on demand.
  • Stream/file processing, де чанки підвантажуються поступово.
  1. Типовий ORM-приклад
  • Завантажується сутність User.
  • User->orders не підтягується одразу.
  • Перший доступ до orders тригерить SQL-запит.
  1. Переваги
  • Швидша початкова відповідь у багатьох сценаріях.
  • Менший memory footprint, коли не всі дані потрібні.
  • Краща масштабованість для складних графів об’єктів.
  1. Компроміси та ризики
  • Приховані запити можуть спричиняти N+1 проблеми продуктивності.
  • Патерни доступу стають менш явними.
  • Lazy loading у tight loops може різко збільшити DB round-trips.
  1. Найкращі практики
  • Використовуйте eager loading, коли наперед відомо, що пов’язані дані потрібні.
  • Профілюйте кількість запитів і latency.
  • Тримайте lazy-межі явними в repository/query шарі.
  • Уникайте lazy-loading всередині serialization/output loops.
  1. Rule of thumb
  • Використовуйте lazy loading для опційних або рідко використовуваних залежностей/даних.
  • Використовуйте eager loading для передбачувано часто потрібних пов’язаних даних.

Lazy loading — потужний інструмент оптимізації продуктивності, але лише за умови прозорості поведінки запитів і свідомої стратегії завантаження.

52. Які найпоширеніші bottlenecks продуктивності в PHP?

PHP

Більшість проблем продуктивності в PHP спричиняє не сама мова, а неефективний I/O, патерни запитів і архітектурні рішення.

  1. Bottlenecks бази даних (найчастіше)
  • N+1 queries при використанні ORM.
  • Відсутні індекси або погані query plans.
  • Over-fetching даних (SELECT *, коли це не потрібно).
  • Довгі транзакції та lock contention.
  1. Мережа і зовнішній I/O
  • Повільні сторонні API без timeouts/retries.
  • Надто багато синхронних outbound-викликів у request path.
  • Відсутність circuit breakers/fallbacks.
  1. Неефективність на рівні застосунку
  • Важка бізнес-логіка виконується на кожному запиті.
  • Повторні дорогі обчислення замість кешування.
  • Надмірна serialization/deserialization або обробка великих payload.
  1. Autoload/bootstrap overhead
  • Великий framework-bootstrap для тривіальних endpoint-ів.
  • Забагато завантажених класів/config providers.
  • Невірно налаштований OPcache.
  1. Overhead файлової системи та логування
  • Часті записи на диск у request path.
  • Блокуюче/надмірно деталізоване логування без async-обробки.
  • Повільні storage volumes у контейнерах/VM.
  1. Тиск на пам’ять
  • Великі in-memory колекції й необмежені масиви.
  • Неефективні цикли на дуже великих датасетах.
  • Long-lived workers, які ненавмисно утримують посилання.
  1. Відсутність/неефективне кешування
  • Відсутність кешу для read-heavy даних.
  • Неправильна стратегія invalidation, що дає stale/frequent misses.
  • Cache stampede під навантаженням.
  1. Як підходити системно
  • Профілюйте перед оптимізацією.
  • Спершу пріоритезуйте найгарячіші endpoints/queries.
  • Додавайте query optimization + caching + async offloading.
  • Моніторте p95/p99 latency, DB time, cache hit ratio і error rates.

У PHP-системах найшвидші виграші зазвичай дають тюнінг запитів, стратегія кешування та зменшення синхронного I/O у request path.

53. Як профілювати PHP-застосунок?

PHP

Профілювання — це процес вимірювання, куди реально витрачаються час виконання, CPU, пам’ять і I/O, щоб оптимізація базувалася на фактах, а не на здогадках.

  1. Що виміряти насамперед
  • Латентність запитів (p50/p95/p99)
  • Час роботи з БД і кількість запитів
  • Тривалість зовнішніх API-викликів
  • Використання пам’яті та пікове використання
  • Гарячі функції/шляхи коду
  1. Поширені інструменти профілювання PHP
  • Blackfire - production-friendly профілювання і рекомендації продуктивності.
  • Xdebug (profiler mode) - детальні traces/callgrind для локального аналізу.
  • Tideways/XHProf family - профілювання на рівні функцій із low-overhead опціями.
  • APM tools (Datadog/New Relic тощо) для розподіленої видимості запитів.
  1. Практичний workflow профілювання

  2. Відтворіть повільний endpoint/job на реалістичних даних.

  3. Зніміть profile trace.

  4. Визначте головні внески в затримку (DB, зовнішній I/O, CPU-heavy функції).

  5. Оптимізуйте по одному bottleneck за раз.

  6. Перепрофілюйте й порівняйте метрики.

  7. Що зазвичай виявляється hotspot-ами

  • N+1 ORM queries
  • Відсутні індекси / дорогі SQL scans
  • Повторна serialization і обробка великих payload
  • Синхронні мережеві виклики в request path
  • Надмірний framework/bootstrap overhead
  1. Фокус memory-профілювання
  • Великі масиви/колекції, завантажені одразу
  • Long-lived references у workers
  • Непотрібні графи об’єктів і дублювання даних
  1. Найкращі практики
  • Профілюйте в середовищах, близьких до production-поведінки.
  • Робіть benchmark до і після кожної оптимізації.
  • Відстежуйте регресії в CI/CD через performance budgets для критичних endpoint-ів.
  • Комбінуйте code profiling із DB profiling (EXPLAIN, slow query logs).

Профілювання перетворює тюнінг продуктивності на вимірюваний інженерний процес і є найнадійнішим способом безпечно покращити швидкість PHP-застосунку.

54. Як працює кешування (Redis, Memcached)?

PHP

Кешування зберігає попередньо обчислені або часто запитувані дані у швидкому сховищі (зазвичай у пам’яті), щоб уникати повторних дорогих операцій, як-от запити до БД або важкі обчислення.

  1. Як працює кешування (базовий flow)

  2. Застосунок отримує запит на дані.

  3. Перевіряє кеш за ключем.

  4. Якщо cache hit: швидко повертає кешоване значення.

  5. Якщо cache miss: завантажує з джерела (DB/API), записує в кеш із TTL, повертає значення.

  6. Поширені cache-backend-и

  • Redis: in-memory сховище даних із багатими структурами, опціями персистентності, pub/sub і розподіленими можливостями.
  • Memcached: простий розподілений in-memory key-value кеш, орієнтований на високошвидкісне ефемерне кешування.
  1. Типові сценарії кешування в PHP
  • Кешування результатів запитів
  • Зберігання сесій
  • Кешування response/fragment
  • Лічильники rate limiting
  • Локи та ключі ідемпотентності
  • Обчислені/конфігураційні довідкові дані
  1. Важливі концепти дизайну кешу
  • Стратегія ключів: передбачуваний namespacing і версіонування (user:42:v2).
  • TTL: обирайте час життя відповідно до мінливості даних.
  • Invalidation: явна інвалідація під час записів, коли важлива актуальність.
  • Модель узгодженості: приймайте eventual consistency там, де це доречно.
  1. Поширені помилки
  • Cache stampede (багато одночасних miss).
  • Застарілі дані через слабку стратегію invalidation.
  • Завеликі значення й поганий дизайн ключів.
  • Сприйняття кешу як джерела істини.
  1. Найкращі практики
  • Кешуйте лише дорогі/високочастотні читання.
  • Використовуйте короткі, розумні TTL і jitter, щоб зменшити синхронне протермінування.
  • Додавайте захист від stampede (locks, request coalescing, stale-while-revalidate).
  • Моніторте hit rate, latency, eviction та використання пам’яті.
  • Зберігайте БД як source of truth; кеш — це шар прискорення.

Кешування через Redis/Memcached — один із найефективніших способів зменшити затримку та навантаження на базу даних у production PHP-системах.

55. Що таке асинхронна обробка в PHP?

PHP

Асинхронна обробка означає винесення повільних або некритичних задач із синхронного HTTP request flow, щоб користувачі отримували швидкі відповіді, а фонова робота виконувалася окремо.

  1. Чому async потрібен
  • Цикли request-response мають залишатися короткими.
  • Деякі операції є дорогими: email-розсилка, обробка файлів, генерація звітів, виклики зовнішніх API.
  • Виконання всього цього inline збільшує латентність і вплив збоїв.
  1. Як це працює в PHP-системах

  2. Основний застосунок отримує запит.

  3. Критичний стан швидко зберігається.

  4. Фоновий job/event відправляється в чергу.

  5. Worker-процес забирає задачу й виконує її асинхронно.

  6. Типові async-навантаження

  • Email/SMS/push-нотифікації
  • Обробка медіа (images/video/PDF)
  • Імпорт/експорт даних
  • Доставка webhook-ів і retry
  • Оновлення пошукового індексу
  • Обробка аналітики/подій
  1. Переваги
  • Нижча користувацька латентність.
  • Краща стійкість (retry, dead-letter queues).
  • Вища пропускна здатність завдяки decoupling важких задач.
  • Чіткіше розділення online і offline роботи.
  1. Компроміси
  • Додаткова операційна складність (queues/workers/monitoring).
  • Eventual consistency між записом і побічними ефектами.
  • Потреба в ідемпотентності та retry-safe обробниках.
  1. Найкращі практики
  • Тримайте payload задач мінімальними (ID, а не повні об’єкти).
  • Робіть обробники ідемпотентними.
  • Налаштовуйте retry/backoff і dead-letter обробку.
  • Моніторте глибину черги, lag воркерів і рівень помилок.
  • Чітко визначайте, які задачі sync-критичні, а які async-відкладені.

У PHP-архітектурі асинхронна обробка — ключова техніка для масштабування користувацького досвіду та надійності під реальним production-навантаженням.

56. Що таке черги (RabbitMQ, Kafka, Redis queues)?

PHP

Черги — це механізми обміну повідомленнями для розв’язування зв’язності між producer-ами та consumer-ами, що дає асинхронну обробку, буферизацію та надійне виконання фонових задач.

  1. Базова концепція черги
  • Producer публікує повідомлення/job.
  • Брокер тимчасово зберігає його.
  • Consumer/worker обробляє його пізніше.
  • Це прибирає важку роботу із синхронного request flow.
  1. Чому черги важливі
  • Згладжують піки трафіку (буферизація).
  • Покращують час відповіді (винесення background-задач).
  • Підвищують надійність через retry та dead-letter handling.
  • Розв’язують компоненти та сервіси.
  1. Поширені технології черг у PHP
  • RabbitMQ: традиційний message broker, потужні патерни маршрутизації, acknowledgements, retry.
  • Kafka: розподілений event log, high-throughput stream processing, replayable повідомлення.
  • Черги на Redis (наприклад, Laravel queues): простий і швидкий варіант для багатьох фонових задач рівня застосунку.
  1. Типові use cases черг у PHP
  • Відправка Email/SMS/push
  • Доставка webhook-ів
  • Обробка файлів/зображень/відео
  • Індексація пошуку
  • Генерація звітів
  • Інтеграційний/event fan-out
  1. Концепти надійності
  • Ack/Nack: підтвердити успіх або запросити повтор.
  • Retry policy: exponential backoff, максимальна кількість спроб.
  • Dead-letter queue (DLQ): ізоляція poison/failing повідомлень.
  • Ідемпотентність: безпечна повторна обробка без дублювання побічних ефектів.
  1. Найкращі практики
  • Тримайте payload повідомлень малими (надавайте перевагу ID, а не великим об’єктам).
  • Версіонуйте схеми повідомлень.
  • Робіть consumer-и ідемпотентними та observable (logs/metrics/tracing).
  • Моніторте глибину черги, lag обробки, failure rate, retry rate.
  • Встановлюйте чіткі SLA для latency обробки.

Черги — фундаментальний будівельний блок для масштабованих і стійких PHP-систем з асинхронними навантаженнями.

57. Що таке event-driven архітектура в PHP?

PHP

Event-driven architecture (EDA) — це стиль, у якому компоненти системи взаємодіють через публікацію та обробку подій, а не через прямі синхронні виклики.

  1. Базова ідея
  • Producer генерує подію (наприклад, OrderPlaced).
  • Зацікавлені consumer-и підписуються й обробляють її незалежно.
  • Паблішеру не потрібно знати, які саме consumer-и існують.
  1. Чому EDA корисна
  • Розв’язує модулі/сервіси.
  • Покращує розширюваність (нові consumer-и можна додати без змін у publisher-і).
  • Підтримує async-обробку і кращу масштабованість.
  • Робить side effects явними як domain/integration events.
  1. Типові сценарії у PHP
  • Замовлення створене -> надіслати email, зарезервувати залишки, опублікувати аналітику.
  • Користувач зареєструвався -> welcome-послідовність, синхронізація з CRM, audit log.
  • Платіж успішний -> генерація інвойсу, нотифікації, фулфілмент.
  1. Типи подій
  • Domain events: бізнес-значущі факти всередині меж домену.
  • Integration events: події, опубліковані для інших сервісів/систем.
  1. Варіанти доставки в PHP-екосистемі
  • In-process event bus/dispatcher (framework-level events).
  • Доставка через queue/broker (RabbitMQ/Kafka/Redis streams/queues) для async і cross-service розподілу.
  1. Ключові аспекти дизайну
  • Ідемпотентні обробники (події можуть бути доставлені більше одного разу).
  • Гарантії порядку (залежать від transport/topic/partition стратегії).
  • Retry і dead-letter policy для помилок.
  • Еволюція схеми/версій payload подій.
  1. Найкращі практики
  • Використовуйте immutable, versioned payload-и подій.
  • Тримайте обробники сфокусованими та незалежними.
  • Сприймайте події як факти (іменування в минулому часі: UserRegistered).
  • Додавайте observability: correlation ID, tracing, метрики processing lag.

EDA в PHP допомагає будувати модульні й масштабовані системи, де workflows можуть еволюціонувати без жорсткої зв’язаності між компонентами.

58. Що таке WebSockets і коли їх використовувати?

PHP

WebSockets — це протокол, який створює постійне двонапрямлене з’єднання між клієнтом і сервером, даючи обмін даними в реальному часі без повторюваного HTTP polling.

  1. Чим WebSockets відрізняються від HTTP
  • HTTP: request/response, зазвичай короткоживучий і ініційований клієнтом.
  • WebSocket: одне довготривале з’єднання, де обидві сторони можуть надсилати повідомлення у будь-який момент.
  1. Коли WebSockets корисні
  • Чати та повідомлення в реальному часі.
  • Live dashboard-и/оновлення моніторингу.
  • Колаборативне редагування та індикатори присутності.
  • Торгові/ринкові фіди, ігрові події, нотифікації.
  1. Чому не варто використовувати WebSockets всюди
  • Додають операційну складність (стан з’єднань, масштабування, маршрутизація).
  • Не потрібні для простих CRUD-сторінок із рідкими оновленнями.
  • У деяких випадках SSE або short polling можуть бути простішими та достатніми.
  1. Архітектурні аспекти для PHP
  • Традиційна модель запитів PHP-FPM неідеальна для довготривалих з’єднань.
  • Поширені підходи: окремі WebSocket-сервери (Ratchet/Swoole/RoadRunner), окремий real-time сервіс + інтеграція PHP-бекенда через Redis/message broker.
  1. Питання масштабування
  • Fan-out з’єднань і ефективність broadcast.
  • Sticky sessions vs спільний pub/sub backplane.
  • Горизонтальне масштабування з Redis/Kafka/NATS-подібними messaging layers.
  1. Безпека й надійність
  • Автентифікуйте WebSocket handshake/session.
  • Валідовуйте схему повідомлень і перевіряйте авторизацію для кожного каналу/topic.
  • Застосовуйте rate limits і захист від зловживань.
  • Обробляйте reconnect, heartbeat і backpressure.
  1. Практичне правило
  • Використовуйте WebSockets, коли low-latency server push — ключова вимога продукту.
  • Віддавайте перевагу простішим HTTP-підходам, коли достатньо near-real-time.

WebSockets — потужний інструмент real-time у PHP-екосистемах, якщо поєднати його з правильним runtime і моделлю масштабування.

59. Як будувати REST API у PHP?

PHP

Побудова REST API у PHP означає надання ресурсів через HTTP із чіткими маршрутами, стандартними методами, передбачуваними status code і консистентними JSON-контрактами.

  1. Базові REST-принципи
  • Resource-орієнтовані endpoints (/users, /orders/{id}).
  • Коректні HTTP-методи: GET, POST, PUT/PATCH, DELETE.
  • Stateless-запити.
  • Узгоджений формат представлення (зазвичай JSON).
  1. Типові шари API в PHP
  • Route/controller layer (HTTP input/output).
  • Validation/auth/middleware layer.
  • Service/use-case layer (бізнес-логіка).
  • Repository/data layer (персистентність).
  1. Ключові аспекти дизайну
  • Стратегія версіонування (/api/v1/... або через headers).
  • Стандартний формат response envelope і помилок.
  • Узгоджені правила pagination/filtering/sorting.
  • Ідемпотентність для релевантних write-операцій.
  1. HTTP-коректність
  • Повертаєте змістовні status code (200, 201, 204, 400, 401, 403, 404, 422, 500).
  • Встановлюйте Content-Type: application/json.
  • Використовуйте caching headers там, де доречно.
  1. Базова безпека
  • Автентифікація (token/JWT/session залежно від контексту).
  • Перевірки авторизації для кожного ресурсу/дії.
  • Валідація вхідних даних і кодування вихідних.
  • Rate limiting і захист від зловживань.
  • CSRF-захист для cookie-based API.
  1. Операційна якість
  • Структуровані логи + request correlation ID.
  • Централізована обробка винятків.
  • Документація OpenAPI/Swagger.
  • Contract/integration тести для критичних endpoint-ів.
  1. Приклад форми endpoint-у
  • POST /api/v1/orders
  • Validate payload -> виконати use case -> повернути 201 Created із тілом ресурсу/локацією.
  1. Практичний guideline
  • Тримайте контролери «тонкими».
  • Не змішуйте бізнес-логіку з HTTP-шаром.
  • Робіть API-контракти явними та стабільними.

Якісний REST API у PHP — це не тільки маршрути, а й узгоджені контракти, безпечна поведінка та операційна надійність.

60. Що таке GraphQL і як він використовується в PHP?

PHP

GraphQL — це мова запитів до API і runtime, де клієнти запитують рівно ті поля, які їм потрібні, із типізованої схеми, замість споживання фіксованих REST-payload-ів.

  1. Ключові концепти GraphQL
  • Schema: строго типізований контракт (типи, поля, аргументи).
  • Queries: операції читання.
  • Mutations: операції запису.
  • Resolvers: PHP-функції/методи, що отримують або обчислюють дані поля.
  1. Чому команди використовують GraphQL
  • Уникає over-fetching/under-fetching, типових для REST.
  • Єдиний endpoint для гнучкого отримання даних.
  • Краща швидкість розробки фронтенду для складних потреб UI у даних.
  • Потужна підтримка introspection та tooling.
  1. Як це використовується у PHP
  • Визначається GraphQL schema у коді/SDL.
  • Імплементуються resolvers, що викликають services/repositories.
  • Виконується query проти schema і повертається JSON-відповідь.
  • У шар виконання інтегруються auth, validation, complexity limits і caching.
  1. Типові варіанти стеку в PHP
  • webonyx/graphql-php (базова GraphQL-реалізація)
  • Framework-інтеграції/адаптери для Laravel/Symfony-екосистем
  1. Компроміси
  • Більша складність, ніж у базового REST для простих API.
  • Потрібні суворі обмеження глибини/складності query, щоб уникати дорогих запитів.
  • Стратегія кешування може бути складнішою, ніж у REST endpoint caching.
  • Дисципліна schema governance/versioning є критичною.
  1. Найкращі практики
  • Тримайте resolvers «тонкими»; делегуйте в application services.
  • Використовуйте патерн DataLoader, щоб уникати N+1 backend-викликів.
  • Забезпечуйте auth на рівні поля/ресурсу, де це потрібно.
  • Обмежуйте depth/complexity запитів і моніторте важкі операції.
  • Публікуйте schema docs і сприймайте зміни schema як контракти.

GraphQL у PHP найбільш ефективний для data-rich продуктів зі складними потребами клієнтів, за умови керування складністю query та governance схеми.

61. Що таке автентифікація API (JWT, OAuth)?

PHP

Автентифікація API перевіряє, хто викликає ваш API і з якими правами. Два поширені підходи: токен-автентифікація на базі JWT і OAuth 2.0 / OpenID Connect.

  1. JWT-автентифікація
  • Після успішного логіну сервер видає підписаний токен (JWT).
  • Клієнт надсилає токен у кожному запиті (зазвичай Authorization: Bearer ...).
  • API перевіряє підпис, строк дії і claims.

Типові JWT claims:

  • sub (subject/user id)
  • exp (час завершення дії)
  • iss/aud (issuer/audience)
  • опційно roles/scopes
  1. OAuth 2.0 (authorization framework)
  • Призначений для делегованого доступу і сторонньої авторизації.
  • Доступ надається через scopes і строк дії токенів.
  • Поширені flow: Authorization Code (+ PKCE), Client Credentials.
  1. OpenID Connect (OIDC)
  • Identity-шар поверх OAuth 2.0.
  • Додає ID token і стандартизовані claims ідентичності користувача.
  1. JWT vs OAuth (практичне розрізнення)
  • JWT — це формат/механізм токена.
  • OAuth — це протокол авторизації.
  • OAuth-токени можуть бути JWT або opaque.
  1. Найкращі практики безпеки
  • Використовуйте лише HTTPS.
  • Робіть access token короткоживучим; безпечно ротуйте refresh token.
  • Перевіряйте підпис, issuer, audience, expiry у кожному запиті.
  • Безпечно зберігайте токени на клієнті (уникайте небезпечних патернів зберігання).
  • За потреби впроваджуйте стратегію revocation/introspection.
  1. Рекомендації для реалізації в PHP
  • Використовуйте перевірені бібліотеки для валідації JWT/OAuth/OIDC.
  • Централізуйте auth middleware.
  • Розділяйте authentication (хто) та authorization (що дозволено).
  • Представляйте дозволи як roles/scopes/policies, що перевіряються на рівні ресурсу.

Сильна API-автентифікація в PHP — це коректність протоколів, гігієна життєвого циклу токенів і сувора валідація кожного захищеного endpoint-у.

62. Що таке rate limiting і безпека API?

PHP

Rate limiting — це механізм контролю, який обмежує кількість запитів від клієнта за певне вікно часу. Це ключова частина ширшої безпеки API.

  1. Чому rate limiting потрібен
  • Запобігає зловживанням і brute-force атакам.
  • Захищає backend-ресурси від перевантаження.
  • Забезпечує справедливе використання між клієнтами/тенантами.
  • Зменшує вплив помилкових або зловмисних інтеграцій.
  1. Поширені стратегії rate limiting
  • Fixed window (прості лічильники на інтервал).
  • Sliding window (точніший розподіл).
  • Token bucket / leaky bucket (дружні до burst-навантажень зі сталими лімітами).
  1. Де застосовуються ліміти
  • Per IP address
  • Per API key/client id
  • Per user/account/tenant
  • Per endpoint sensitivity (суворіші для auth-endpoint-ів)
  1. Типова реалізація у PHP-стеках
  • Перевірки на рівні middleware через Redis/in-memory counters.
  • Enforcement на reverse proxy/API gateway (Nginx, cloud API gateway).
  • Повернення 429 Too Many Requests із retry-заголовками.
  1. Базова безпека API (поза межами rate limits)
  • Сильна автентифікація (JWT/OAuth/OIDC).
  • Перевірки авторизації на кожен ресурс/дію.
  • Валідація вхідних даних і кодування вихідних.
  • HTTPS всюди + безпечні headers.
  • Обмеження розміру/часу запиту і контроль timeout.
  • Audit logging, виявлення аномалій та alerting.
  1. Найкращі практики
  • Використовуйте багаторівневий захист: gateway + app middleware.
  • Застосовуйте різні квоти залежно від плану/рівня довіри.
  • Додавайте обробку burst і graceful degradation.
  • Захищайте login/token endpoints суворішими правилами та lockout.
  • Моніторте кількість hits по лімітах, заблоковані запити й шаблони атак.

Rate limiting — лише одна опора безпеки API; реальний захист дає комбінація автентифікації, авторизації, валідації та observability.

63. Що таке піраміда тестування в PHP?

PHP

Піраміда тестування — це модель тестової стратегії, яка рекомендує багато швидких низькорівневих тестів і менше повільних високорівневих тестів, щоб збалансувати впевненість, швидкість і вартість підтримки.

  1. Рівні піраміди
  • Основа (найбільша): Unit-тести швидкі, ізольовані тести для функцій/класів/бізнес-правил.
  • Середина: Integration-тести перевіряють взаємодію між модулями (DB, cache, queue, external adapters).
  • Верхівка (найменша): End-to-end/API/UI тести валідують повні користувацькі сценарії через усю систему.
  1. Чому ця модель працює
  • Unit-тести дешеві й швидко виконуються у великій кількості.
  • Integration-тести ловлять проблеми меж і з’єднання компонентів.
  • E2E-тести дають реалістичну впевненість, але вони повільніші й крихкіші.
  1. PHP-специфічне відображення
  • Unit: PHPUnit/Pest із mocks/stubs.
  • Integration: реальні DB-контейнери, repositories, HTTP clients у контрольованому середовищі.
  • E2E/API: тести на рівні запитів до запущеного застосунку/сервісу.
  1. Поширені антипатерни
  • «Морозивний конус»: занадто багато UI/E2E-тестів і замало unit-тестів.
  • Надмірне мокання всього, що знижує впевненість в інтеграції.
  • Відсутність contract-тестів для критичних зовнішніх інтеграцій.
  1. Практичні рекомендації
  • Тримайте більшість тестів на unit-рівні.
  • Додавайте сфокусовані integration-тести навколо критичних меж.
  • Тримайте E2E-набір невеликим, стабільним і бізнес-критичним.
  • Запускайте швидкі набори на кожен commit; важчі — на main/pre-release gates.
  1. Результат

Здорова піраміда дає швидкий зворотний зв’язок розробникам і високу впевненість у релізі без надмірного CI-часу чи флейкової підтримки тестів.

64. Що таке unit-тестування (PHPUnit / Pest)?

PHP

Unit-тестування перевіряє поведінку найменших тестованих частин коду (функцій, методів, класів) в ізоляції від зовнішніх систем.

  1. Що мають покривати unit-тести
  • Бізнес-правила та обчислення.
  • Крайові випадки й валідацію вхідних даних.
  • Поведінку помилок/винятків.
  • Детерміновані гілки логіки.
  1. Принцип ізоляції
  • Unit-тести не повинні залежати від реальної БД, мережі, файлової системи чи queue-сервісів.
  • Зовнішні залежності замінюються test doubles (mocks/stubs/fakes).
  1. Інструменти PHP
  • PHPUnit: класичний і широко прийнятий тестовий фреймворк.
  • Pest: виразний синтаксис, побудований поверх екосистеми PHPUnit.
  1. Простий приклад (стиль PHPUnit)
final class PriceCalculatorTest extends TestCase
{
    public function test_applies_discount(): void
    {
        $calc = new PriceCalculator();
        self::assertSame(90, $calc->applyDiscount(100, 10));
    }
}
  1. Чому unit-тести важливі
  • Швидкий feedback під час розробки.
  • Безпечніший рефакторинг.
  • Краща документація очікуваної поведінки.
  • Раннє виявлення регресій.
  1. Найкращі практики
  • Тримайте тести малими, сфокусованими й детермінованими.
  • Використовуйте чітку структуру arrange-act-assert.
  • Називайте тести за очікуваною поведінкою.
  • Уникайте надмірного мокання внутрішньої логіки.
  • Запускайте unit-тести на кожен commit у CI.

Unit-тестування з PHPUnit/Pest — основа надійної поставки PHP, бо воно дає швидку й точну впевненість у core-логіці.

65. Що таке integration-тестування?

PHP

Integration-тестування перевіряє, що кілька компонентів коректно працюють разом (наприклад, логіка застосунку + база даних + кеш + зовнішні адаптери), залишаючись вужчим за повні end-to-end тести.

  1. На чому фокусується integration-тестування
  • Межі модулів і їхня взаємодія.
  • Коректність збереження/отримання даних.
  • Поведінка інфраструктурних адаптерів.
  • Коректність конфігурації та зв’язування компонентів.
  1. Чим відрізняється від unit-тестів
  • Unit-тести ізолюють один компонент і мокають залежності.
  • Integration-тести використовують реальні або максимально близькі до реальних залежності, щоб перевірити взаємодії.
  1. Типові integration-сценарії в PHP
  • Repository з реальною тестовою БД/контейнером.
  • HTTP client adapter проти sandbox/mock-сервера.
  • Flow публікації/споживання черги у контрольованому середовищі.
  • Взаємодія framework route + middleware + controller + service.
  1. Чому integration-тести важливі
  • Ловлять проблеми, які моки не показують (невідповідність SQL-схеми, serialization bugs, помилки конфігурації).
  • Підвищують впевненість у критичних межах.
  • Зменшують продакшн-сюрпризи від інфраструктурної зв’язаності.
  1. Найкращі практики
  • Запускайте на виділеній тестовій інфраструктурі (ізольована DB/cache).
  • Контролюйте setup/teardown даних детерміновано.
  • Тримайте фокус: одна integration-проблематика на тест.
  • Уникайте зайвої мережевої залежності, коли достатньо contract stubs.
  • Додавайте integration-suite в CI для критичних шляхів.
  1. Компроміс
  • Повільніші й «важчі» за unit-тести, тому мають бути менш чисельними й таргетованими.

Integration-тести — це міст між швидкою впевненістю unit-рівня і повною системною впевненістю в PHP delivery pipelines.

66. Що таке мокінг і навіщо він потрібен?

PHP

Мокінг — це техніка тестування, у якій реальні залежності замінюються контрольованими test doubles, щоб ізолювати модуль, який тестується, і перевіряти взаємодії.

  1. Чому мокінг потрібен
  • Ізолювати бізнес-логіку від зовнішніх систем (DB, HTTP, queue, filesystem).
  • Робити тести швидкими й детермінованими.
  • Симулювати рідкісні/помилкові сценарії, які складно відтворити на реальних сервісах.
  • Перевіряти контракти взаємодії (метод викликано з очікуваними аргументами).
  1. Поширені типи test doubles
  • Stub: повертає наперед задані значення.
  • Mock: перевіряє очікувані взаємодії/виклики.
  • Fake: полегшена робоча реалізація (наприклад, in-memory repository).
  • Spy: записує виклики для подальших перевірок.
  1. Концепт прикладу в PHP

Тестуємо OrderService, мокнувши PaymentGatewayInterface і OrderRepositoryInterface, далі перевіряємо:

  • сервіс повертає очікуваний результат
  • gateway викликається один раз із коректною сумою
  • repository->save() викликається з очікуваним станом сутності
  1. Де мокінг доречний
  • Unit-тести domain/application services.
  • Тестування error-path для зовнішніх залежностей.
  • Перевірка контрактів на межах модулів.
  1. Де мокінгу недостатньо
  • Інтеграційна поведінка з реальною БД/мережевими протоколами.
  • Проблеми wiring/конфігурації фреймворку.
  • Характеристики продуктивності та семантика транзакцій.
  1. Найкращі практики
  • Мокайте лише зовнішні межі, не внутрішню pure-логіку.
  • Тримайте очікування сфокусованими на спостережуваній поведінці.
  • Надавайте перевагу інтерфейсам для mockable залежностей.
  • Поєднуйте unit + integration тести (мокінг сам по собі не є повною стратегією).

Мокінг критично важливий для швидких, ізольованих unit-тестів у PHP, але його треба балансувати integration-тестами для впевненості в реальній системі.

67. Що таке code coverage?

PHP

Code coverage — це метрика, яка показує, які частини вихідного коду були виконані автоматизованими тестами.

  1. Що вимірює coverage
  • Line coverage: виконані рядки.
  • Branch/condition coverage: виконані гілки рішень.
  • Function/method coverage: виконані callable-одиниці.
  1. Чому це корисно
  • Підсвічує непокриті тестами ділянки.
  • Допомагає пріоритезувати, де бракує тестів.
  • Підтримує оцінку ризику регресій під час рефакторингу.
  1. Що coverage НЕ гарантує
  • Високий coverage автоматично не означає високу якість тестів.
  • Тести можуть виконувати код без перевірки коректної поведінки.
  • Критичні edge cases можуть бути пропущені навіть за високих відсотків.
  1. Інструментарій у PHP
  • PHPUnit/Pest можуть генерувати coverage-звіти.
  • Зазвичай використовують драйвери Xdebug або PCOV.
  • Звіти можуть формуватися у форматах text, HTML або CI.
  1. Практичне використання в командах
  • Відстежуйте тренди з часом, а не женіться за одним «магічним» числом.
  • Встановлюйте розумні мінімальні пороги для критичних модулів.
  • Використовуйте coverage deltas у PR-перевірках, щоб запобігати регресіям тестів.
  1. Найкращі практики
  • Спершу фокусуйтеся на тестуванні критичної бізнес-логіки та ризикових шляхів.
  • Поєднуйте coverage з mutation testing/static analysis, де це можливо.
  • Переглядайте якість assertions, а не лише виконані рядки.
  • Не допускайте flakey або low-value тестів для «накрутки» coverage.

Code coverage — корисний сигнал повноти тестів, але його слід інтерпретувати разом із якістю тестів і контекстом ризиків, а не як самодостатню ціль.

68. Що таке статичний аналіз (PHPStan, Psalm)?

PHP

Статичний аналіз перевіряє PHP-код без виконання, щоб рано виявити проблеми типів, потенційні баги, мертвий код і порушення архітектури.

  1. Що знаходить статичний аналіз
  • Невідповідності типів і неможливі типи.
  • Проблеми nullability та доступу до undefined variable/property/method.
  • Некоректні return types і небезпечні касти.
  • Недосяжний/мертвий код і частину патернів неправильного використання API.
  1. Основні інструменти
  • PHPStan: широко прийнятий, рівні строгості, сильна інтеграція в екосистему.
  • Psalm: просунута система типів, потужний inference, опції taint analysis.
  1. Чому це цінно
  • Виявляє дефекти до runtime і до того, як їх покриють тести.
  • Підвищує безпеку рефакторингу у великих кодових базах.
  • Заохочує сильнішу типізацію й чіткіші контракти.
  • Зменшує production-інциденти через базові помилки типів/потоків.
  1. Як команди це використовують
  • Запускають у CI на кожен PR.
  • Починають із помірної строгості й поступово підвищують.
  • Підтримують baseline для legacy-проблем, водночас не допускаючи нових.
  1. Найкращі практики
  • Послідовно додавайте type hints/return types.
  • Використовуйте generic-анотації, де потрібно (колекції, репозиторії).
  • Виправляйте root-cause проблем типізації замість подавлення попереджень.
  • Тримайте конфіг аналізу версіонованим і рев’юйте як код.
  1. Статичний аналіз vs тести
  • Статичний аналіз не замінює тести.
  • Він доповнює unit/integration тести, доводячи структурну/типову коректність у шляхах, які тести можуть пропускати.

Статичний аналіз із PHPStan/Psalm — високоефективний quality gate для сучасних PHP-проєктів, особливо під час безперервного рефакторингу.

69. Що таке Rector і як його використовують для рефакторингу?

PHP

Rector — це інструмент автоматизованого рефакторингу для PHP, який трансформує вихідний код за наперед визначеними та кастомними правилами, допомагаючи безпечно модернізувати кодові бази у великому масштабі.

  1. Що робить Rector
  • Застосовує AST-базовані трансформації коду.
  • Оновлює синтаксис/можливості між версіями PHP.
  • Рефакторить патерни використання фреймворків/бібліотек.
  • Автоматизує повторювані механічні зміни.
  1. Типові сценарії використання
  • Оновлення зі старих версій PHP до новіших стандартів.
  • Міграція застарілих API на актуальні альтернативи.
  • Впровадження сучасних мовних конструкцій (typed properties, constructor promotion тощо).
  • Масштабне очищення кодової бази перед впровадженням строгого статичного аналізу.
  1. Як це використовують на практиці

  2. Налаштовують rector.php з наборами правил.

  3. Запускають Rector на вибраних шляхах.

  4. Переглядають згенерований diff.

  5. Запускають тести/статичний аналіз.

  6. Комітять інкрементальні, безпечні порції змін.

  7. Чому команди використовують Rector

  • Значно пришвидшує модернізацію.
  • Зменшує людські помилки в повторюваних рефакторингах.
  • Підтримує консистентний стиль рефакторингу між модулями.
  1. Найкращі практики
  • Запускайте Rector на сфокусованих ділянках, а не на всій legacy-кодовій базі одразу.
  • Тримайте зміни невеликими й зручними для рев’ю.
  • Завжди валідуйте результат тестами + PHPStan/Psalm після трансформацій.
  • Фіксуйте версію Rector у tooling для відтворюваності.
  • Поєднуйте автоматичний рефакторинг із ручним архітектурним рев’ю.
  1. Важливе обмеження
  • Rector добре обробляє механічні трансформації, але не замінює архітектурне судження або доменно-специфічні рішення з редизайну.

Rector найбільш ефективний як частина пайплайну рефакторингу разом зі статичним аналізом і тестами, а не як окремий «one-click migration» інструмент.

70. Що таке контроль coding standards (PHP-CS-Fixer)?

PHP

Контроль coding standards — це практика автоматичної перевірки та виправлення правил стилю коду, щоб кодова база залишалася консистентною, читабельною та зручною для рев’ю.

  1. Чому coding standards важливі
  • Покращують читабельність у команді.
  • Зменшують стильовий шум у pull request.
  • Дозволяють фокусувати code review на логіці, а не на форматуванні.
  • Підтримують цілісність довгоживучих кодових баз.
  1. Що робить PHP-CS-Fixer
  • Сканує PHP-файли за налаштованими правилами стилю.
  • Автоматично переписує порушення форматування/стилю.
  • Підтримує стандартні rule sets (наприклад, PSR-12) і кастомні правила.
  1. Типовий workflow
  • Налаштувати правила у .php-cs-fixer.php.
  • Запускати checker у CI, щоб не допускати drift.
  • Запускати fixer локально/pre-commit для автоформатування змінених файлів.
  1. Поширені категорії правил
  • Порядок imports і видалення невикористаних imports.
  • Стиль spacing/indentation/braces.
  • Нормалізація синтаксису масивів/функцій.
  • Правила строгої типізації та пріоритету сучасного синтаксису.
  1. Найкращі практики
  • Рано узгодьте єдиний стандарт для всього проєкту.
  • Додайте auto-fix у developer workflow (pre-commit/hooks/editor integration).
  • Тримайте CI як gate контролю (--dry-run режим).
  • Великі переформатування робіть окремо від feature-змін, щоб diffs були чистими.
  1. Суміжні інструменти
  • PHP-CS-Fixer (auto-fix форматування/стилю).
  • PHP_CodeSniffer (перевірка правил і аналіз coding standards).
  • Поєднуйте стильові інструменти з PHPStan/Psalm для якості понад форматування.

Контроль coding standards інструментами на кшталт PHP-CS-Fixer — недорогий спосіб підвищити підтримуваність і швидкість команди у PHP-проєктах.

71. Що таке CI/CD pipeline для PHP-застосунків?

PHP

CI/CD pipeline — це автоматизований workflow, який послідовно збирає, тестує, перевіряє та деплоїть PHP-застосунки від commit до production.

  1. Цілі CI (Continuous Integration)
  • Швидко валідувати кожну зміну.
  • Рано ловити баги через автоматичні перевірки.
  • Тримати main-гілку завжди готовою до релізу.
  1. Типові CI-етапи для PHP

  2. Встановлення залежностей (composer install).

  3. Статичні перевірки (PHPStan/Psalm, coding standards).

  4. Unit/integration тести (PHPUnit/Pest).

  5. Збірка/пакування артефактів (Docker image або deploy bundle).

  6. Цілі CD (Continuous Delivery/Deployment)

  • Безпечно доставляти валідовані артефакти в середовища.
  • Автоматизувати rollout-кроки та мінімізувати ручні помилки.
  • Підтримувати швидкий rollback під час інцидентів.
  1. Типові CD-етапи
  • Деплой у staging.
  • Запуск smoke/health checks.
  • Промоція того самого артефакту у production.
  • Моніторинг post-deploy метрик і логів.
  1. PHP-специфічні найкращі практики
  • Використовуйте відтворювані інсталяції на основі lockfile.
  • Збирайте immutable artifacts один раз і перевикористовуйте між середовищами.
  • Запускайте DB-міграції за контрольованою стратегією.
  • Тримайте secrets/config поза артефактом.
  • Використовуйте патерни zero-downtime rollout (blue-green/canary/rolling).
  1. Quality gates
  • Обов’язковий успішний статус тестів.
  • Поріг статичного аналізу.
  • Перевірки безпеки (dependency audit/SAST).
  • Опційно performance smoke checks для критичних endpoint-ів.
  1. Результат

Надійний CI/CD pipeline підвищує частоту релізів, стабільність і впевненість команди, зменшуючи production-ризики в PHP delivery.

72. Як деплоїти PHP-застосунки?

PHP

Деплой PHP-застосунків означає доставку протестованого артефакту у production з передбачуваною runtime-конфігурацією, мінімальним простоєм і безпечним rollback.

  1. Поширені цільові середовища деплою
  • Традиційні VM/bare metal з Nginx/Apache + PHP-FPM.
  • Контейнерні платформи (Docker, Kubernetes, ECS).
  • Платформні сервіси (PaaS/serverless-варіанти).
  1. Рекомендований flow деплою

  2. Зібрати immutable artifact (image/package) у CI.

  3. Запустити тести/статичні перевірки/security scans.

  4. Задеплоїти артефакт у staging.

  5. Виконати smoke checks і health checks.

  6. Промотувати той самий артефакт у production.

  7. Runtime-основи

  • Конфігурація та secrets на основі середовища (без хардкоду).
  • Коректні PHP-розширення та налаштування OPcache.
  • Перевірена на старті підключеність DB/cache/queue.
  • Увімкнені структуровані логи й моніторинг.
  1. Стратегія міграцій БД
  • Застосовуйте backward-compatible міграції до перемикання трафіку.
  • Використовуйте підхід expand-and-contract для ризикових змін схеми.
  • Тримайте міграційні скрипти версіонованими й повторюваними.
  1. Техніки zero/low-downtime
  • Blue-green, rolling або canary деплої.
  • Graceful reload для воркерів (PHP-FPM/process manager).
  • Перемикання трафіку через load balancer на основі health checks.
  1. Стратегія rollback
  • Швидкий rollback до попереднього артефакту/версії.
  • Контрольований rollback БД або план forward-fix.
  • Post-deploy вікно моніторингу з alerting.
  1. Найкращі практики
  • Ніколи не деплойте напряму з локальної машини.
  • Тримайте процес деплою автоматизованим і auditable.
  • Використовуйте infrastructure as code там, де можливо.
  • Чітко розділяйте build-time і runtime concerns.

Якісний деплой PHP — це інженерна система: відтворювані артефакти, безпечна механіка rollout, observability і надійний rollback.

73. Що таке blue-green deployment?

PHP

Blue-green deployment — це стратегія релізу, за якої підтримуються два однакові production-середовища: одне активне (обслуговує трафік), інше — очікує (кандидат для наступного релізу).

  1. Як це працює
  • Blue: поточне live-середовище.
  • Green: нова версія, задеплоєна та перевірена паралельно.
  • Після успішних перевірок трафік перемикається з Blue на Green.
  • Старе середовище залишається доступним для швидкого rollback.
  1. Чому команди це використовують
  • Мінімізує downtime під час деплою.
  • Знижує ризик релізу завдяки майже миттєвому rollback.
  • Дає реалістичну pre-switch перевірку на production-подібному стеку.
  1. Типовий rollout flow

  2. Задеплоїти новий PHP-реліз у неактивне середовище.

  3. Запустити health checks/smoke tests/стратегію міграцій.

  4. Перемкнути load balancer/router на нове середовище.

  5. Моніторити error rates/latency.

  6. Тимчасово тримати попереднє середовище для rollback.

  7. Ключові аспекти для PHP-застосунків

  • Session-стратегія має підтримувати перемикання середовищ (shared Redis/session store).
  • Статичні assets/версіонування мають бути сумісними між обома середовищами.
  • DB-зміни мають бути backward-compatible у вікні переходу.
  • Queue workers і cron jobs мають уникати дублювання побічних ефектів.
  1. Переваги
  • Швидкий шлях rollback.
  • Безпечніші деплої для high-traffic систем.
  • Чітке розділення «поточний» vs «кандидат» реліз.
  1. Компроміси
  • Вища інфраструктурна вартість (два середовища).
  • Більша операційна складність навколо сумісності даних/схеми.

Blue-green — сильний deployment-патерн для PHP production-систем, де критичні uptime і швидкість rollback.

74. Що таке стратегія rollback?

PHP

Стратегія rollback — це наперед визначений план швидкого повернення до попередньої стабільної версії, коли деплой спричиняє інциденти (помилки, регресії, просідання продуктивності, проблеми з даними).

  1. Чому стратегія rollback критична
  • Скорочує тривалість інциденту та вплив на користувачів.
  • Запобігає хаотичним аварійним діям під час збоїв.
  • Підвищує впевненість у частих релізах.
  1. Що має бути rollback-ready
  • Версія application artifact/image.
  • Версія інфраструктури/конфігурації.
  • Стан feature flags/toggles.
  • План сумісності міграцій бази даних.
  1. Поширені підходи rollback
  • Artifact rollback: повторний деплой попереднього known-good білду.
  • Traffic rollback: перемикання назад на попереднє середовище (blue-green/canary revert).
  • Feature rollback: вимкнення проблемного feature flag без повного редеплою.
  1. Реальність rollback бази даних
  • Rollback БД часто є найскладнішою частиною.
  • Віддавайте перевагу backward-compatible міграціям: спершу expand, потім contract.
  • Використовуйте forward-fix, коли повний schema rollback ризикований.
  1. Операційний чекліст
  • Визначте пороги-тригери rollback (error rate, latency, failed checks).
  • Тримайте попередній реліз готовим до миттєвого деплою.
  • Автоматизуйте rollback-кроки в pipeline/runbooks.
  • Перевіряйте health після rollback і продовжуйте моніторинг.
  1. Найкращі практики
  • Регулярно відпрацьовуйте rollback у staging.
  • Тримайте релізи невеликими, щоб зменшувати blast radius.
  • Поєднуйте rollout і rollback з observability (logs/metrics/traces).
  • Документуйте ownership і flow ухвалення рішень під час інцидентів.

Сильна стратегія rollback — ключовий механізм надійності для PHP production delivery, особливо в середовищах із високою частотою деплоїв.

75. Що таке serverless PHP (Laravel Vapor, Bref)?

PHP

Serverless PHP — це модель виконання, у якій ваш PHP-код працює в керованих хмарних функціях/платформах без прямого керування традиційними серверами.

  1. Ключова ідея
  • Ви деплоїте код/функції, а не парк VM.
  • Хмарний провайдер бере на себе provisioning, scaling і значну частину операцій.
  • Оплата зазвичай базується на часі виконання та кількості запитів.
  1. Поширені serverless-опції для PHP
  • Laravel Vapor: платформа для Laravel на AWS (Lambda, керовані інтеграції).
  • Bref: open-source runtime/tooling для запуску PHP на AWS Lambda (framework-agnostic підтримка).
  1. Чому команди використовують serverless PHP
  • Швидке горизонтальне auto-scaling.
  • Менше операційного навантаження (менше patching/provisioning).
  • Економічність для пікового або низького базового трафіку.
  • Швидший time-to-production для API/backoffice-навантажень.
  1. Архітектурні наслідки
  • Stateless-виконання функцій.
  • Винесений стан (DB, Redis, object storage, queues).
  • Event-driven тригери (HTTP, черги, cron, object events).
  • Треба враховувати cold starts і ліміти виконання.
  1. Найкращі сценарії використання
  • API зі змінним трафіком.
  • Фонові job-и/події.
  • Планові задачі та легка автоматизація.
  • MVP і команди, що оптимізують швидкість доставки.
  1. Компроміси
  • Обмеження платформи/runtime і timeouts.
  • Ризик vendor lock-in.
  • Вплив cold-start latency на частину endpoint-ів.
  • Debugging/observability можуть потребувати додаткового налаштування.
  1. Найкращі практики
  • Тримайте функції невеликими та сфокусованими.
  • Оптимізуйте bootstrap-time і обсяг залежностей.
  • Використовуйте async-черги для довготривалої роботи.
  • Налаштовуйте надійні logging/metrics/tracing із першого дня.
  • Проєктуйте ідемпотентні обробники й retry-safe workflows.

Serverless PHP з Vapor/Bref — сильний варіант для масштабованих low-ops архітектур, коли характеристики навантаження відповідають serverless-моделі.

76. Що таке мікросервіси vs моноліт у PHP?

PHP

Моноліт і мікросервіси — це архітектурні стилі для побудови систем. У PHP обидва підходи можуть бути ефективними, якщо вибір зроблено з урахуванням розміру команди, складності домену й операційної зрілості.

  1. Моноліт (один deployable-застосунок)
  • Одна кодова база/одиниця деплою, що містить кілька бізнес-можливостей.
  • Спільний runtime і зазвичай спільна база даних.

Переваги

  • Простіша розробка, тестування та деплой.
  • Нижчий операційний overhead.
  • Простіший локальний дебаг і транзакції між модулями.

Недоліки

  • Важче еволюціонувати, якщо межі між частинами слабкі.
  • Великі деплої можуть підвищувати ризик релізу.
  • Масштабування часто грубозернисте (масштабується весь застосунок).
  1. Мікросервіси (кілька незалежно deployable сервісів)
  • Система поділена на невеликі сервіси, узгоджені з бізнес-доменами.
  • Кожен сервіс володіє своєю логікою і часто своїм сховищем даних.

Переваги

  • Незалежне масштабування/деплой для кожного сервісу.
  • Чіткі межі відповідальності.
  • Гнучкість технологій/runtime для окремих сервісів.

Недоліки

  • Вища складність (мережа, observability, auth, retry, консистентність даних).
  • Складніша локальна розробка і cross-service дебаг.
  • Потрібна суттєва DevOps/platform зрілість.
  1. PHP-специфічна практична реальність
  • Багато команд успішно стартують із modular monolith.
  • Мікросервіси стають доцільними, коли чіткі bounded contexts і масштаб команди виправдовують операційну вартість.
  1. Рекомендація для вибору
  • Обирайте моноліт/modular monolith, коли: продукт на ранній стадії, команда мала/середня, і найважливіша швидкість.
  • Обирайте мікросервіси, коли: домени чітко відокремлюються, потреби масштабування сильно різняться, а платформні можливості зрілі.
  1. Поширена помилка
  • Занадто ранній старт із мікросервісами створює випадкову складність без бізнес-вигоди.

У PHP-екосистемах прагматичний шлях зазвичай такий: спочатку добре структурований моноліт, потім вибіркове виділення сервісів, коли цього об’єктивно вимагають обмеження.

77. Що таке архітектура modular monolith?

PHP

Modular monolith — це один deployable-застосунок, структурований як чітко розділені внутрішні модулі з явними межами й контрактами.

  1. Ключова ідея
  • Одна одиниця застосунку/runtime/deployment.
  • Кілька бізнес-модулів (bounded contexts) всередині.
  • Сильні внутрішні межі для зменшення зв’язаності.
  1. Чим відрізняється
  • Від класичного моноліту: modular monolith суворо дотримується меж модулів і правил залежностей.
  • Від мікросервісів: зберігає єдину одиницю деплою та уникає складності розподілених систем.
  1. Типова структура модулів у PHP
  • Modules/Orders/...
  • Modules/Billing/...
  • Modules/Users/...

Кожен модуль містить власні:

  • domain-логіку
  • application/use-case сервіси
  • infrastructure adapters
  • HTTP/API handlers (або маповані інтерфейси)
  1. Чому команди це обирають
  • Швидша розробка, ніж у мікросервісах.
  • Простіший локальний дебаг і транзакції.
  • Нижчий операційний overhead.
  • Хороший шлях до domain-driven організації та майбутнього виділення сервісів.
  1. Практики дотримання меж
  • Комунікуйте між модулями через інтерфейси/події, а не прямий доступ до internals.
  • Уникайте спільних mutable «god» utility між модулями.
  • Використовуйте статичний аналіз/тести для контролю напряму залежностей.
  • Тримайте ownership бази даних явним (навіть якщо фізично вона спільна).
  1. Коли це вдалий вибір
  • Продукт і команда ростуть, але складність мікросервісів ще передчасна.
  • Потрібне сильне розділення доменів за простої моделі деплою.
  1. Шлях еволюції
  • Почніть із modular monolith.
  • Виділяйте окремі модулі в сервіси лише тоді, коли тиск масштабування/команди/ownership реальний і вимірюваний.

Modular monolith часто є найпрагматичнішою архітектурою для PHP-команд, які хочуть чисті межі вже сьогодні без передчасного overhead розподілених систем.

78. Які поширені вразливості PHP трапляються в реальних проєктах?

PHP

Більшість реальних інцидентів безпеки в PHP виникають через небезпечну обробку вводу, слабкий auth/session контроль і проблеми залежностей/конфігурації, а не через саму мову.

  1. Ін’єкційні вразливості
  • SQL Injection через небезпечну побудову запитів.
  • Command Injection, коли недовірений ввід передається в shell/system виклики.
  • Header/LDAP/NoSQL-подібні ін’єкції в інтеграційних шарах.
  1. Cross-site вразливості
  • XSS (stored/reflected/DOM) через відсутність контекстного escaping у виводі.
  • CSRF у cookie-auth flow без token і SameSite-захисту.
  1. Помилки автентифікації та авторизації
  • Слабка робота з паролями або відсутність MFA для критичних ролей.
  • Broken access control (IDOR/BOLA): користувач отримує доступ до чужих ресурсів, змінюючи ID.
  • Відсутність server-side перевірок авторизації на чутливих endpoint-ах.
  1. Проблеми сесій і токенів
  • Небезпечні cookie-flags (відсутні Secure, HttpOnly, SameSite).
  • Session fixation/hijacking через погану ротацію ID.
  • Витік або надто довгий lifetime API-токенів без стратегії revocation.
  1. Ризики обробки файлів
  • Небезпечні file uploads (без валідації типу/вмісту, можливі executable upload-и).
  • Path traversal (../) через неперевірені шляхи.
  • Небезпечна десеріалізація або unsafe parsing недовірених файлів.
  1. Ризики конфігурації та залежностей
  • Увімкнений debug mode у production.
  • Експоновані secrets у repo/logs/environment dumps.
  • Застарілі залежності з відомими CVE.
  • Неправильно налаштовані CORS/CSP/security headers.
  1. Як системно зменшувати ризики
  • Строга валідація вводу + контекстне кодування виводу.
  • Prepared statements і безпечні query-шари.
  • Централізовані authz-політики та перевірки deny-by-default.
  • Безпечне керування життєвим циклом сесій/токенів.
  • Dependency scanning/patching і hardening production-конфігурації.
  • Регулярне security-тестування (SAST/DAST), логування й incident playbooks.

Безпека в PHP-проєктах — це передусім дисципліна безпечного дизайну, safe defaults і безперервної верифікації коду, runtime та операцій.

79. Як виявляти витоки пам’яті в PHP?

PHP

У PHP «витоки пам’яті» часто не є класичними постійними витоками на рівні скриптового коду, а проявляються як ріст споживання пам’яті через довгоживучі процеси, утримувані посилання, великі in-memory буфери, витоки в розширеннях або фрагментацію алокатора.

  1. Спершу визначте, де з’являється leak-подібна поведінка
  • FPM/request-модель: пам’ять має повертатися після завершення запиту; ріст зазвичай вказує на проблеми рівня воркерів або надмірні запити.
  • Довгоживучі воркери (queue consumers, daemons, Swoole/RoadRunner): утримання стану між job-ами — часте джерело.
  • CLI batch-скрипти: необмежені масиви/кеші можуть імітувати витоки.
  1. Інструментуйте пам’ять у коді
  • Використовуйте memory_get_usage(true) і memory_get_peak_usage(true) навколо ключових етапів pipeline.
  • Логуйте пам’ять на кожну ітерацію/job, щоб виявити монотонний тренд росту.
  • Додавайте лічильники оброблених елементів, щоб корелювати пам’ять з розміром навантаження.
  1. Використовуйте runtime/process-рівневу діагностику
  • Відстежуйте RSS воркерів у часі через ps, top, container metrics або APM.
  • Порівнюйте PHP-рівень usage з OS-рівнем пам’яті, щоб помітити поведінку алокатора/фрагментації.
  • У FPM моніторте пам’ять pool-воркерів і шаблони їх рестартів.
  1. Використовуйте профайлери та спеціалізовані інструменти
  • Xdebug/Blackfire/Tideways для allocation-hotspots і важких call-path.
  • Valgrind/ASan для витоків у C-розширеннях або native-рівні (debug-білди, повільніше, але точно).
  • Framework debug toolbars/profilers для memory snapshots на рівні запиту.
  1. Поширені root causes, які варто перевірити
  • Static/global масиви, що накопичують дані між job-ами.
  • Event listeners/closures, які ненавмисно захоплюють великі об’єкти.
  • ORM identity maps або query results, що утримуються надто довго.
  • Копії великих strings/JSON payload під час трансформацій.
  • Циклічні посилання + відкладений GC у довгих циклах.
  1. Патерни зменшення після виявлення
  • Обробляйте дані chunk-ами/stream-ами замість повного завантаження в пам’ять.
  • Явно робіть unset() великих змінних і періодично викликайте gc_collect_cycles() у довгих циклах.
  • Пересоздавайте worker-процес після N job-ів/часу (--max-jobs, supervisor restarts).
  • Налаштовуйте розумні memory limits і fail-fast поведінку.
  • Оновлюйте залежності/розширення, коли native leaks виправлені upstream.

Практичний підхід: вимірюйте тренд, ізолюйте hotspot, підтверджуйте профілюванням і контролюйте життєві межі довгоживучих процесів.

80. Як оптимізувати використання пам’яті?

PHP

Оптимізація пам’яті в PHP здебільшого полягає в контролі життєвого циклу даних, зменшенні зайвих копій і використанні streaming/chunked-обробки замість завантаження всього одразу.

  1. Обробляйте дані інкрементально
  • Для великих наборів даних віддавайте перевагу генераторам (yield) замість побудови великих масивів.
  • Читайте файли/стріми построково або chunk-ами.
  • Розбивайте читання з БД на сторінки (LIMIT/OFFSET або cursor/chunk API) для batch-задач.
  1. Уникайте зайвих копій
  • Мінімізуйте конкатенацію рядків у щільних циклах; використовуйте buffering-стратегії.
  • Уникайте повторного array_merge великих масивів усередині циклів.
  • Обережно ставтеся до трансформацій, що дублюють великі структури.
  1. Звільняйте пам’ять раніше в довгоживучих скриптах
  • Робіть unset() великих тимчасових змінних після використання.
  • Розбивайте роботу на обмежені ітерації; очищуйте стан після кожної.
  • Для циклічних посилань у довгих циклах періодично викликайте gc_collect_cycles().
  1. Обирайте ефективні патерни доступу до даних
  • Вибирайте в SQL лише потрібні колонки, а не SELECT *.
  • Гідратуйте lightweight DTO/масиви, коли повні ORM-моделі не потрібні.
  • Обережно використовуйте lazy-loading; уникайте N+1 запитів і надмірних графів об’єктів.
  1. Використовуйте runtime-ліміти та контроль життєвого циклу воркерів
  • Встановлюйте розумний memory_limit, щоб fail-fast замість деградації хоста.
  • Для queue-воркерів робіть рестарт після N job-ів/часу, щоб уникати довгострокового memory drift.
  • Моніторте тренд пам’яті через memory_get_usage(true) і OS-метрики.
  1. Кешуйте розумно, а не бездумно
  • Кешуйте лише дорогі обчислення з високою цінністю.
  • Зберігайте компактні cache payload-и; за потреби стискайте.
  • Використовуйте TTL/invalidation, щоб уникати необмеженого росту кешу.
  1. Профілюйте до і після
  • Використовуйте Xdebug/Blackfire/Tideways/APM, щоб знаходити реальні hotspots.
  • Спочатку оптимізуйте виміряні bottleneck-и; уникайте передчасних micro-оптимізацій.

На практиці найбільший виграш дають streaming/chunking, контроль життєвого циклу об’єктів і запобігання великим тимчасовим алокаціям.

81. Як розвернути рядок без built-in функцій?

PHP

Базова ідея: пройти від кінця рядка до початку та побудувати новий рядок посимвольно.

<?php
function reverseString(string $s): string
{
    $result = '';
    $length = strlen($s);

    for ($i = $length - 1; $i >= 0; $i--) {
        $result .= $s[$i];
    }

    return $result;
}

Складність:

  • Час: O(n)
  • Додаткова пам’ять: O(n) для результату

Нотатки для співбесіди:

  • Ця байт-орієнтована версія підходить для ASCII.
  • Для UTF-8/multibyte-рядків індексація по байтах може ламати символи, тому потрібен multibyte-safe підхід.
82. Як видалити дублікати з масиву?

PHP

Стандартний підхід — відстежувати вже побачені значення в hash map і залишати тільки першу появу.

<?php
function removeDuplicates(array $input): array
{
    $seen = [];
    $result = [];

    foreach ($input as $value) {
        $key = is_scalar($value) || $value === null
            ? (string) $value . ':' . gettype($value)
            : serialize($value);

        if (!isset($seen[$key])) {
            $seen[$key] = true;
            $result[] = $value;
        }
    }

    return $result;
}

Чому ця версія зручна для співбесіди:

  • Зберігає порядок вставки.
  • Працює в середньому за лінійний час: O(n).
  • Обробляє scalar-значення, null і складні значення через serialize.

Якщо дозволені built-in функції, array_unique() коротший, але ручна логіка hash-set краще демонструє фундаментальні знання.

83. Як знайти друге найбільше число?

PHP

Надійне рішення за один прохід відстежує найбільше та друге найбільше різні значення під час сканування масиву.

<?php
function secondLargest(array $numbers): ?int
{
    $max = null;
    $second = null;

    foreach ($numbers as $n) {
        if (!is_int($n)) {
            continue;
        }

        if ($max === null || $n > $max) {
            if ($max !== $n) {
                $second = $max;
            }
            $max = $n;
            continue;
        }

        if ($n !== $max && ($second === null || $n > $second)) {
            $second = $n;
        }
    }

    return $second;
}

Поведінка:

  • Повертає null, якщо немає другого найбільшого різного значення (наприклад, [5], [7, 7]).
  • Часова складність: O(n).
  • Просторова складність: O(1).
84. Як перевірити, чи є рядок паліндромом?

PHP

Паліндром читається однаково зліва направо і справа наліво. Ефективно: порівнювати символи з обох кінців, рухаючись до центру.

<?php
function isPalindrome(string $s): bool
{
    $left = 0;
    $right = strlen($s) - 1;

    while ($left < $right) {
        if ($s[$left] !== $s[$right]) {
            return false;
        }
        $left++;
        $right--;
    }

    return true;
}

Складність:

  • Час: O(n)
  • Пам’ять: O(1)

Нотатки для співбесіди:

  • Це байт-орієнтована версія, яка підходить для ASCII.
  • Для UTF-8 потрібен multibyte-safe підхід перед індексацією символів.
  • Уточніть, чи треба ігнорувати пробіли, пунктуацію та регістр; якщо так — спочатку нормалізуйте вхід.
85. Як перевірити, чи є число простим?

PHP

Число n є простим, якщо має рівно два додатні дільники: 1 і n.
Ефективна перевірка: перевіряти дільники лише до sqrt(n).

<?php
function isPrime(int $n): bool
{
    if ($n < 2) {
        return false;
    }

    if ($n === 2) {
        return true;
    }

    if ($n % 2 === 0) {
        return false;
    }

    $limit = (int) sqrt($n);
    for ($i = 3; $i <= $limit; $i += 2) {
        if ($n % $i === 0) {
            return false;
        }
    }

    return true;
}

Складність:

  • Час: O(sqrt(n))
  • Пам’ять: O(1)

Це стандартне рішення для співбесіди: коректне, достатньо швидке й просте для пояснення.

86. Як реалізувати факторіал через рекурсію?

PHP

Рекурсивний факторіал використовує визначення n! = n * (n - 1)! з базовим випадком 0! = 11! = 1).

<?php
function factorial(int $n): int
{
    if ($n < 0) {
        throw new InvalidArgumentException('Factorial is undefined for negative numbers.');
    }

    if ($n === 0 || $n === 1) {
        return 1;
    }

    return $n * factorial($n - 1);
}

Складність:

  • Час: O(n)
  • Пам’ять: O(n) через стек рекурсії.

Нотатка для співбесіди: ітеративна версія використовує O(1) стек-пам’яті й безпечніша для дуже великих n.

87. Як реалізувати сортування вручну?

PHP

Для співбесіди наочний ручний приклад — Bubble Sort: багаторазово міняємо місцями сусідні елементи, якщо вони стоять у неправильному порядку.

<?php
function bubbleSort(array $arr): array
{
    $n = count($arr);

    for ($i = 0; $i < $n - 1; $i++) {
        $swapped = false;

        for ($j = 0; $j < $n - 1 - $i; $j++) {
            if ($arr[$j] > $arr[$j + 1]) {
                $tmp = $arr[$j];
                $arr[$j] = $arr[$j + 1];
                $arr[$j + 1] = $tmp;
                $swapped = true;
            }
        }

        if (!$swapped) {
            break;
        }
    }

    return $arr;
}

Складність:

  • Найгірший/середній час: O(n^2)
  • Найкращий випадок (вже відсортовано з early break): O(n)
  • Додаткова пам’ять: O(1) (ігноруючи семантику копіювання виходу)

Якщо запитають про ефективніший алгоритм, поясніть Merge Sort (O(n log n)) або Quick Sort у середньому (O(n log n)).

88. Як згенерувати послідовність Фібоначчі?

PHP

Найпрактичніший підхід — ітеративний: стартуємо з 0, 1 і щоразу додаємо суму двох попередніх чисел.

<?php
function fibonacciSequence(int $count): array
{
    if ($count <= 0) {
        return [];
    }

    if ($count === 1) {
        return [0];
    }

    $result = [0, 1];

    for ($i = 2; $i < $count; $i++) {
        $result[] = $result[$i - 1] + $result[$i - 2];
    }

    return $result;
}

Складність:

  • Час: O(n)
  • Пам’ять: O(n) для зберігання послідовності

Нотатка для співбесіди:

  • Рекурсивний Fibonacci без memoization має експоненційну складність і зазвичай неприйнятний для performance-чутливих відповідей.
  • Якщо потрібне лише n-те значення, пам’ять можна зменшити до O(1), зберігаючи лише два попередні числа.
89. Як знайти найчастіший елемент?

PHP

Використайте frequency map (hash table): підрахуйте кількість входжень кожного значення, потім поверніть ключ із максимальною частотою.

<?php
function mostFrequentElement(array $items): mixed
{
    if ($items === []) {
        return null;
    }

    $freq = [];
    $bestKey = null;
    $bestCount = 0;

    foreach ($items as $item) {
        $key = is_scalar($item) || $item === null
            ? (string) $item . ':' . gettype($item)
            : serialize($item);

        if (!isset($freq[$key])) {
            $freq[$key] = ['value' => $item, 'count' => 0];
        }

        $freq[$key]['count']++;

        if ($freq[$key]['count'] > $bestCount) {
            $bestCount = $freq[$key]['count'];
            $bestKey = $key;
        }
    }

    return $bestKey !== null ? $freq[$bestKey]['value'] : null;
}

Складність:

  • Час: O(n)
  • Пам’ять: O(k), де k — кількість різних елементів

Поведінка при однаковій частоті: ця реалізація повертає перший елемент, який досяг найвищої частоти.

90. Як спроєктувати high-load PHP-систему?

PHP

Для high-load PHP-систем головний принцип — зробити застосунок stateless, винести важку роботу з request-path і масштабуватися горизонтально за надійною інфраструктурою.

  1. Базова архітектура
  • Stateless PHP-інстанси застосунку за load balancer-ом.
  • Nginx/Envoy + PHP-FPM (або RoadRunner/Swoole, коли це виправдано).
  • Окремі шари даних, кешу, черг і object storage.
  1. Стратегія даних
  • Primary DB для запису + read replicas; розділення read/write шляхів.
  • Коректні індекси, оптимізація запитів і моніторинг slow query.
  • Partitioning/sharding лише тоді, коли вичерпане масштабування одного вузла.
  1. Шари кешування
  • CDN/edge cache для статики й кешованих динамічних відповідей.
  • Redis/Memcached для application-data і «гарячих» результатів запитів.
  • Чітка cache invalidation політика (TTL + event-based invalidation).
  1. Асинхронна обробка
  • Виносьте дорогі задачі в черги (email, звіти, обробка медіа).
  • Використовуйте ідемпотентні воркери з retry і dead-letter queues.
  • Тримайте HTTP-запити короткими й передбачуваними.
  1. Надійність і стійкість
  • Timeouts, circuit breakers, bulkheads для зовнішніх залежностей.
  • Graceful degradation, коли некритичні сервіси падають.
  • Health checks, auto-restarts і rolling deployments.
  1. Observability
  • Централізовані логи з correlation IDs.
  • Метрики: p95/p99 latency, error rate, queue lag, DB/cache saturation.
  • Трейсинг для multi-service request-path.
  1. Операційні практики
  • Capacity planning і load testing перед піковими подіями.
  • Blue-green/canary релізи для зниження ризику.
  • Security hardening і rate limiting на edge та app-рівнях.

Масштабований PHP-дизайн — це насамперед дисципліна інфраструктури й архітектури: stateless app-tier, ефективний доступ до даних, агресивне кешування й асинхронне фонове виконання.

91. Як масштабувати PHP горизонтально?

PHP

Горизонтальне масштабування в PHP означає додавання більшої кількості однакових app-вузлів і гарантію, що будь-який запит може обробити будь-який вузол без залежності від локального стану.

  1. Зробіть application-tier stateless
  • Зберігайте сесії в Redis/DB, а не на локальному диску.
  • Перенесіть завантажені файли в shared/object storage (наприклад, S3-сумісне).
  • Node-local кеші мають бути опційними, а не source of truth.
  1. Розмістіть вузли за load balancer
  • Використовуйте L4/L7 load balancer (Nginx, HAProxy, cloud LB).
  • Увімкніть health checks і автоматичне вилучення unhealthy-вузлів.
  • Sticky sessions — тимчасовий обхідний шлях; краще справді stateless-дизайн.
  1. Масштабуйте read-heavy залежності
  • Додайте DB read replicas і коректно маршрутизуйте read-трафік.
  • Додайте distributed cache (Redis/Memcached), щоб розвантажити primary DB.
  • Використовуйте CDN для статики та кешованих відповідей.
  1. Контролюйте фонові навантаження
  • Використовуйте queue-based workers для важких job-ів.
  • Масштабуйте воркери незалежно від HTTP app-вузлів.
  • Робіть job-и ідемпотентними та retry-safe.
  1. Стандартизуйте runtime через контейнери/образи
  • Immutable images для консистентних деплоїв.
  • Autoscaling-політики на основі CPU, пам’яті та latency-сигналів.
  • Централізоване керування config/secrets.
  1. Observability і сигнали масштабування
  • Відстежуйте p95/p99 latency, saturation, error rate, queue lag.
  • Моніторте тиск на DB connection pool і cache hit ratio.
  • Використовуйте ці метрики для тригерів autoscaling і capacity planning.

На практиці горизонтально масштабувати PHP просто, коли стан винесено назовні, а інфраструктура бере на себе розподіл, health і еластичність.

92. Як обслуговувати мільйони користувачів?

PHP

Обслуговування мільйонів користувачів — це завдання системного дизайну, а не один PHP-трюк. Рішення полягає в багатошаровому масштабуванні edge, app, data та operations.

  1. Розподіл трафіку та edge
  • Глобальний CDN для статичних assets і кешованих API-відповідей.
  • Load balancers з autoscaled stateless PHP app-вузлами.
  • Rate limiting і bot protection на edge.
  1. Архітектура застосунку
  • За потреби розділяйте bottleneck-и моноліту на bounded services.
  • Мінімізуйте синхронний request-path; важкі задачі виносьте в черги.
  • Для критичних write-операцій використовуйте idempotency keys.
  1. Data-layer у масштабі
  • Primary DB для запису, кілька read replicas для read-трафіку.
  • Агресивне індексування й тюнінг запитів; уникайте ORM anti-patterns.
  • Partitioning/sharding для дуже великих датасетів і hot-tenant-ів.
  1. Стратегія кешування
  • Багатошаровий кеш: CDN -> Redis/Memcached -> DB.
  • Кешуйте hot objects, computed views і дорогі запити.
  • Сильні правила invalidation, щоб уникати застарілих критичних даних.
  1. Асинхронна та event-driven обробка
  • Queue workers для email, нотифікацій, медіа, аналітичних pipeline.
  • Retry з backoff, dead-letter queues та ідемпотентні обробники.
  • Стрімінг подій для downstream-consumers замість блокування запитів.
  1. Надійність і стійкість
  • Graceful degradation для некритичних функцій під навантаженням.
  • Timeout budgets і circuit breakers для залежностей.
  • Multi-AZ деплой і протестовані failover-процедури.
  1. Observability та дисципліна ємності
  • SLO для latency/error; відстеження p95/p99 і saturation.
  • Постійне load/stress тестування перед великими релізами.
  • Прогнозування ємності на основі реальних патернів використання.

На масштабі «мільйони» успіх визначається передбачуваною архітектурою, контрольованим зростанням даних і сильними операційними практиками більше, ніж оптимізаціями на рівні мови.

93. Як спроєктувати стратегію кешування?

PHP

Хороша стратегія кешування починається з патернів доступу та вимог консистентності, а не лише з вибору технології.

  1. Визначте, що саме кешувати
  • Результати дорогих DB-запитів.
  • Агреговані/обчислені API-відповіді.
  • Сесійний і авторизаційний контекст (коли це безпечно).
  • Статичні/конфігураційні/довідкові дані з низькою частотою змін.
  1. Використовуйте багатошарове кешування
  • Edge/CDN cache для статики і кешованих HTTP-відповідей.
  • Application cache (Redis/Memcached) для hot objects і результатів запитів.
  • In-process/opcache оптимізації для коду та immutable-конфігурації.
  1. Обирайте правильні cache-патерни
  • Cache-aside для read-heavy даних (найпоширеніше).
  • Write-through/write-behind для окремих випадків консистентності/продуктивності.
  • Read-through, якщо cache-провайдер підтримує прозоре завантаження.
  1. Ретельно проєктуйте ключі та TTL
  • Namespaced-ключі: entity:{id}:v{version}.
  • Різні TTL залежно від мінливості даних і критичності для бізнесу.
  • Додавайте jitter до TTL, щоб зменшити thundering herd.
  1. Явно керуйте invalidation
  • Event-driven invalidation після записів.
  • Versioned keys для простої логічної інвалідації.
  • Tag-based invalidation, коли підтримується.
  1. Захищайтеся від збоїв кешу
  • Fallback-шлях, якщо кеш недоступний (degraded, але функціонально).
  • Request coalescing/locking, щоб запобігти stampede.
  • Warm-up критичних ключів після deploy/restart.
  1. Постійно вимірюйте і тюньте
  • Моніторте hit ratio, latency, eviction rate, memory pressure.
  • Відстежуйте інциденти stale reads і вартість cache miss.
  • Оптимізуйте на основі реальних production traces.

Сильна стратегія кешування — це баланс: максимізувати hit rate і виграш у latency, зберігаючи коректність та передбачувану invalidation-поведінку.

94. Чим сучасні PHP-фреймворки (Laravel, Symfony) відрізняються внутрішньо?

PHP

Laravel і Symfony мають багато спільних основ (життєвий цикл HTTP-запиту, DI, концепції middleware/events), але відрізняються архітектурною філософією, дефолтами та моделлю розширення.

  1. Базова філософія
  • Symfony: component-first, явна конфігурація, висока composability.
  • Laravel: інтегрований developer experience, convention-heavy дефолти, швидша доставка «з коробки».
  1. Dependency Injection і контейнер
  • Symfony має скомпільований DI-контейнер із сильною compile-time валідацією та оптимізацією.
  • Laravel використовує дуже динамічний service container з runtime-resolution і auto-wiring патернами, орієнтованими на ergonomics розробника.
  1. Модель конфігурації
  • Symfony: configuration-centric (yaml/xml/php), environment-specific bundles, явний wiring.
  • Laravel: convention + service providers + facades; багато можливостей увімкнено з мінімальною конфігурацією.
  1. Внутрішній HTTP-pipeline
  • У Symfony request-flow центрований навколо HttpKernel та listeners event dispatcher-а.
  • У Laravel request-flow орієнтований на middleware-pipeline з виразною інтеграцією routes/controllers.
  1. Дефолти ORM/data-layer
  • Symfony часто використовує Doctrine ORM (Data Mapper pattern, явна поведінка unit-of-work).
  • Laravel постачається з Eloquent (Active Record pattern, швидка CRUD-ергономіка).
  1. Структура екосистеми
  • Компоненти Symfony широко перевикористовуються окремо в усій PHP-екосистемі.
  • Екосистема Laravel тісно інтегрована (queues, jobs, scheduler, Horizon, Nova-подібні tooling-патерни).
  1. Продуктивність і production-профіль
  • Обидва можуть бути production-grade у масштабі.
  • Symfony частіше робить акцент на передбачуваності й явному контролі у великих enterprise-системах.
  • Laravel робить акцент на швидкості імплементації та цілісному developer workflow.

Коротко: Symfony оптимізує під явну архітектуру і композицію компонентів; Laravel — під інтегровану продуктивність і швидку delivery розробки фіч.

95. Як працює routing у фреймворках?

PHP

Routing мапить вхідний HTTP-запит на конкретний handler (controller/action/closure) за методом, path-патерном, host та опційними обмеженнями.

  1. Фаза визначення маршрутів
  • Фреймворк завантажує таблицю маршрутів під час boot (з файлів/attributes/annotations).
  • Кожен маршрут зберігає method(s), path pattern, handler, middleware і metadata.
  • Багато фреймворків попередньо компілюють/кешують route definitions для швидшого lookup.
  1. Фаза зіставлення запиту
  • Router отримує нормалізовані request path + method.
  • Спершу намагається зіставити статичні маршрути, потім динамічні параметризовані.
  • Перевіряються constraints (regex, host, scheme, locale).
  1. Витяг параметрів
  • Динамічні сегменти на кшталт /users/{id} витягуються зі шляху.
  • Значення кастяться/валідуються (явно або через framework binding rules).
  • Для відсутніх опціональних параметрів застосовуються значення за замовчуванням.
  1. Middleware і guards
  • До виконання handler-а запускається route/group/global middleware-chain.
  • Типові перевірки: auth, rate limiting, CSRF, permissions, tenant resolution.
  • Middleware може short-circuit і повернути відповідь раніше.
  1. Controller dispatch
  • Контейнер резолвить залежності контролера.
  • Route params + injected services передаються в action method.
  • Action повертає response object/data для serialization.
  1. Reverse routing
  • Фреймворк може генерувати URL з route names + params.
  • Це прибирає hardcoded URL і підвищує безпеку рефакторингу.
  1. Міркування продуктивності
  • Route cache/precompilation у production.
  • Надавайте перевагу конкретним/статичним маршрутам замість надто широких wildcard-патернів.
  • Тримайте middleware-chain мінімальним для hot-endpoint-ів.

Внутрішньо routing — це по суті індексований pipeline pattern-matching і dispatch, обгорнутий middleware та dependency injection.

96. Як внутрішньо працює middleware pipeline?

PHP

Middleware pipeline — це chain-of-responsibility: кожен middleware отримує request і callable next, після чого або передає керування далі, або одразу повертає response.

  1. Побудова pipeline
  • Фреймворк збирає global, group і route-specific middleware.
  • Порядок middleware визначається (можуть діяти правила пріоритету).
  • Фінальний handler (controller/action) встановлюється останнім кроком.
  1. Модель виконання
  • Концептуальна сигнатура middleware: handle(Request $request, Closure $next): Response.
  • Middleware може зробити pre-processing і викликати $next($request).
  • Після повернення з next middleware може зробити post-processing response.
  1. Short-circuit поведінка
  • Middleware може повернути response без виклику $next.
  • Типові випадки: провал auth, провал CSRF, перевищений rate-limit, maintenance mode.
  • Це зупиняє виконання нижчих middleware/controller.
  1. Вкладений call stack
  • Ланцюг часто будується обгортанням closures від останнього до першого.
  • Виконання «спускається» шляхом request, потім «розмотується» шляхом response.
  • Це дозволяє cross-cutting concerns: logging, timing, header injection.
  1. Обробка помилок і винятків
  • Exception middleware/handler може перехоплювати та нормалізувати помилки.
  • Деякі фреймворки розміщують error handling поза middleware stack як top-level kernel logic.
  • Узгоджене мапування помилок робить API-відповіді передбачуваними.
  1. Поширені відповідальності middleware
  • Перевірки authentication/authorization.
  • Request validation/sanitization.
  • Rate limiting і anti-abuse контроль.
  • Tracing, logging, metrics, correlation IDs.
  • CORS/security headers і трансформація відповіді.
  1. Міркування продуктивності
  • Тримайте ланцюг мінімальним на hot-routes.
  • Розміщуйте дешеві reject-fast перевірки на початку.
  • Уникайте важкого синхронного I/O в загальних middleware.

Внутрішньо middleware — це впорядкована композиція callable, яка централізує cross-cutting concerns навколо request/response потоку.

97. Як під капотом працює резолвінг залежностей?

PHP

Резолвінг залежностей у сучасних PHP-фреймворках виконується DI-контейнером, який будує об’єкти на основі bindings і metadata конструктора, зазвичай через reflection і кешовані визначення.

  1. Container bindings
  • Interfaces/abstracts мапляться на concrete-реалізації.
  • Bindings можуть бути singleton, scoped або transient.
  • Factories/closures можуть визначати кастомну логіку побудови.
  1. Запит на резолвінг
  • Фреймворк запитує у контейнера тип (controller, service, middleware тощо).
  • Контейнер перевіряє, чи вже існує інстанс (для singleton/scoped lifetime).
  • Якщо ні, починає будувати граф об’єктів.
  1. Інтроспекція конструктора
  • Контейнер аналізує параметри конструктора (reflection або скомпільована metadata).
  • Для class-typed параметрів рекурсивно резолвить залежності.
  • Для scalar/config значень використовує явні параметри, env/config bindings або значення за замовчуванням.
  1. Рекурсивна побудова графа об’єктів
  • Залежності резолвляться в depth-first порядку.
  • Виявлення циклічних залежностей запобігає нескінченній рекурсії.
  • Опціональні залежності можуть бути nullable/defaulted, якщо не забінджені.
  1. Життєвий цикл і кешування
  • Singleton-и кешуються після першого створення.
  • Scoped-інстанси кешуються в межах request/job scope.
  • Деякі контейнери компілюють metadata для швидшого резолвінгу в production.
  1. Method/action injection
  • Крім конструкторів, фреймворки можуть інжектити залежності в controller actions, command handlers і middleware methods.
  • Route params і container services об’єднуються під час dispatch.
  1. Типові failure modes
  • Unbound interface/abstract.
  • Неоднозначний або неінстанційований ланцюг залежностей.
  • Scalar-параметри конструктора без defaults/bindings.
  • Циклічні залежності між сервісами.

Під капотом DI-резолвінг — це детермінована побудова графа з правилами життєвого циклу, reflection/metadata і кешуванням для продуктивності.

98. Які best practices сучасної PHP-розробки у 2026 році?

PHP

Сучасні best practices PHP у 2026 році фокусуються на строгій інженерній дисципліні: сильна типізація, автоматизовані quality gates, безпечні дефолти та спостережувані production-системи.

  1. Використовуйте актуальні можливості мови усвідомлено
  • declare(strict_types=1); у коді застосунку.
  • Typed properties, return types, enums, readonly/value-object патерни.
  • По можливості надавайте перевагу явним контрактам замість динамічної магії.
  1. Архітектура й організація коду
  • Модульні межі (domain/application/infrastructure або еквівалент).
  • Чітке розділення бізнес-логіки і framework glue code.
  • Dependency inversion через інтерфейси для testability.
  1. Автоматизація якості
  • CI зі статичним аналізом (PHPStan/Psalm) на високому рівні строгості.
  • Консистентний стиль коду через PHP-CS-Fixer/Pint.
  • Unit + integration + contract тести з реалістичними fixtures.
  1. Продуктивність і runtime-ефективність
  • PHP 8.3/8.4+ з OPcache і налаштованими параметрами FPM/process manager.
  • Спочатку профілюйте (Blackfire/XHProf/APM), потім оптимізуйте hotspots.
  • Використовуйте кешування/черги, щоб тримати синхронний request-path «легким».
  1. Безпека за замовчуванням
  • Prepared statements, контекстне escaping виводу, CSRF-захист.
  • Керування secrets поза репозиторієм; ротація ключів і least privilege.
  • Сканування вразливостей залежностей у CI.
  1. Операційна зрілість
  • Структуровані логи, метрики, трейсинг, correlation IDs.
  • Моніторинг на основі SLO з контролем alert fatigue.
  • Безпечні релізи: canary/blue-green і процедури rollback.
  1. Гігієна залежностей і екосистеми
  • Тримайте Composer-залежності актуальними з контрольованим ритмом оновлень.
  • Фіксуйте й аудіть критичні пакети.
  • Уникайте зайвої framework-coupling у core domain code.
  1. Командні конвенції
  • ADR для важливих рішень і чіткі стандарти code review.
  • Правила backward compatibility для public/internal API.
  • Документація поруч із кодом для онбордингу та incident response.

Найсильніші PHP-команди у 2026 році ставляться до здоров’я кодової бази як до продукту: типізовано, протестовано, спостережувано та безперервно покращувано.

99. Які інструменти є обов’язковими для сучасного PHP-розробника?

PHP

Ефективний сучасний PHP-toolkit покриває написання коду, якість, дебаг, delivery та operations.

  1. База мови та керування пакетами
  • Runtime PHP 8.3/8.4+.
  • Composer для залежностей та autoloading.
  • Локальні інструменти середовища: Docker/DDEV/Lando або нативний відтворюваний setup.
  1. Якість коду і статичний аналіз
  • PHPStan або Psalm для статичного аналізу.
  • PHP-CS-Fixer або Pint для coding standards.
  • PHP_CodeSniffer там, де потрібні кастомні стандарти.
  1. Testing stack
  • PHPUnit або Pest для unit/integration тестів.
  • Бібліотеки для mocking/test doubles за потреби.
  • Coverage-звітність, інтегрована в CI.
  1. Дебаг і профілювання
  • Xdebug для покрокового дебагу.
  • Blackfire/Tideways/XHProf/APM profiler для performance bottlenecks.
  • Інструменти структурованого логування та централізований перегляд логів.
  1. Фреймворк і DX-tooling
  • Laravel Artisan або Symfony Console tooling.
  • Framework-specific debug/profiler утиліти.
  • API-інструменти: Postman/Insomnia + OpenAPI validation.
  1. Інструменти даних та інфраструктури
  • Redis і DB CLI-інструменти (redis-cli, psql, mysql) для діагностики.
  • Dashboards моніторингу черг/воркерів.
  • Tooling для міграцій і керування схемою.
  1. CI/CD і автоматизація
  • GitHub Actions/GitLab CI або еквівалент.
  • Автоматизовані lint, static analysis, tests, security scan gates.
  • Автоматизація деплою з можливістю rollback.
  1. Безпека та гігієна залежностей
  • composer audit і/або SCA-сканери.
  • Secret scanning і pre-commit hooks.
  • SAST/DAST там, де цього вимагає профіль ризику.
  1. Observability та operations
  • Стек метрик, трейсингу й алертингу (Prometheus/Grafana/APM).
  • Відстеження помилок (Sentry/Bugsnag).
  • Кореляція логів через request IDs.

Ключовий набір — той, що забезпечує швидкі feedback loops: перевірки якості коду, надійні тести, безпечну доставку і видимість production.

100. Як підтримувати PHP-кодову базу в довгостроковій перспективі?

PHP

Довгострокова підтримуваність досягається поєднанням технічних стандартів, архітектурної дисципліни та безперервного операційного зворотного зв’язку.

  1. Тримайте архітектуру явною
  • Забезпечуйте чіткі модульні межі й ownership.
  • Відділяйте domain-логіку від framework/infrastructure деталей.
  • Мінімізуйте приховану зв’язаність і глобальний стан.
  1. Ставте читабельність вище за «хитрість»
  • Невеликі сфокусовані класи/функції з чіткими назвами.
  • Узгоджені конвенції по всій кодовій базі.
  • Віддавайте перевагу явній поведінці над магічними абстракціями.
  1. Серйозно ставтеся до type safety
  • strict_types=1 там, де це можливо.
  • Сильна типізація параметрів/повернень/властивостей.
  • Статичний аналіз (PHPStan/Psalm) як обов’язковий CI-gate.
  1. Будуйте стійкий тестовий портфель
  • Швидкі unit-тести для core-логіки.
  • Integration-тести для DB/зовнішніх меж.
  • Contract-тести для API/events, які спільно використовуються з іншими сервісами.
  1. Контролюйте залежності та оновлення
  • Регулярний ритм оновлення залежностей замість рідкісних «big-bang» апгрейдів.
  • Ведення changelog-ів і трекінг deprecations для framework/runtime змін.
  • Проактивно прибирайте невикористані пакети й «мертві» абстракції.
  1. Проєктуйте для безпечних змін
  • Правила backward compatibility для public API.
  • Feature flags для ризикових rollout.
  • Міграції та зміни даних із планами rollback/repair.
  1. Інституціоналізуйте процес якості коду
  • Code review checklist (correctness, security, performance, readability).
  • Автоматичне форматування/linting для зменшення шуму в рев’ю.
  • ADR для ключових рішень, щоб зберігати контекст у часі.
  1. Операційний feedback loop
  • Production observability: логи, метрики, трейсинг, error tracking.
  • Post-incident review, що дає конкретні покращення коду/процесів.
  • SLO-базована пріоритезація, щоб надійність залишалась видимою.
  1. Захищайте командну безперервність
  • Актуальна документація для setup, архітектури та runbooks.
  • Онбординг-гайди та спільні інженерні стандарти.
  • Зменшення ризику «єдиного експерта» через knowledge sharing і ротацію.

Підтримувана PHP-кодова база не є статичною; її постійно курирують через стандарти, автоматизацію та свідому спрощуваність.