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

Middle: питання на співбесіді з теми «PHP 8+»

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

4 питання

Атрибути (PHP 8.0) - структуровані метадані, прикріплені до класів, методів, властивостей, параметрів, функцій і констант. Синтаксис #[...]. На відміну від анотацій у PHPDoc, атрибути - частина мови: перевіряються синтаксично, мають класи й автодоповнення.

Оголошення атрибута:

#[Attribute(Attribute::TARGET_METHOD)]
final class Route
{
    public function __construct(
        public string $path,
        public string $method = 'GET',
    ) {}
}

Використання:

final class UserController
{
    #[Route('/users', method: 'GET')]
    public function index(): Response { /* ... */ }
}

Читання через Reflection:

foreach ((new ReflectionClass(UserController::class))->getMethods() as $method) {
    foreach ($method->getAttributes(Route::class) as $attribute) {
        $route = $attribute->newInstance();   // створює об'єкт Route з аргументами
        $router->add($route->method, $route->path, [$method->class, $method->name]);
    }
}

Важливо: атрибут сам нічого не робить. Це лише дані, які хтось має прочитати. Об'єкт атрибута створюється лише при newInstance().

Вбудовані атрибути PHP: #[\Override] (8.3) - перевірка, що метод справді перевизначає батьківський; #[\SensitiveParameter] (8.2) - приховати значення параметра в стек-трейсах (паролі); #[\Deprecated] (8.4); #[\NoDiscard] (8.5) - попередження, якщо результат функції проігноровано; #[\AllowDynamicProperties].

У Laravel: атрибути контейнера (#[Config('app.name')], #[CurrentUser], #[Storage('s3')]), атрибути моделей (#[ObservedBy], #[ScopedBy]), атрибути Livewire (#[Url], #[Locked], #[Computed]).

Продуктивність: читання через Reflection не безкоштовне - фреймворки кешують результат (кеш маршрутів, скомпільований контейнер).

Докладніше в документації: Атрибути

PHP 8.4 (листопад 2024) - головні зміни:

Property hooks - логіка читання й запису властивості без геттерів і сеттерів:

public string $email {
    set => mb_strtolower($value);
}

Асиметрична видимість - різні права на читання й запис: public private(set) string $status.

new без дужок у ланцюжку:

$name = new Profile($user)->displayName();   // раніше: (new Profile($user))->displayName()

Нові функції масивів: array_find(), array_find_key(), array_any(), array_all():

$admin = array_find($users, fn (User $u) => $u->isAdmin());
$allPaid = array_all($orders, fn (Order $o) => $o->isPaid());

Лінива ініціалізація об'єктів (lazy objects) - вбудована підтримка ghost- і proxy-об'єктів, що ініціалізуються при першому зверненні. Корисно для ORM і контейнерів.

#[\Deprecated] - позначати власні функції й методи застарілими, і PHP сам видаватиме E_USER_DEPRECATED при виклику.

Інше:

  • Новий DOM API з підтримкою HTML5 (Dom\HTMLDocument).
  • mb_trim(), mb_ucfirst(), mb_lcfirst().
  • BCMath отримав об'єктний API (BcMath\Number) з перевантаженням операторів.
  • request_parse_body() - розбір тіла для PUT/PATCH.

Застарілим стало: неявно nullable параметри - function f(Type $x = null) тепер видає попередження; правильно ?Type $x = null. Це одна з найчастіших змін при оновленні старого коду.

Докладніше в документації: Реліз PHP 8.4

PHP 8.5 (листопад 2025) - головні нововведення:

Оператор конвеєра |> - передає значення ліворуч у callable праворуч, без проміжних змінних і вкладених викликів:

$slug = $title
    |> trim(...)
    |> mb_strtolower(...)
    |> (fn (string $s) => preg_replace('/\s+/', '-', $s));

// замість
$slug = preg_replace('/\s+/', '-', mb_strtolower(trim($title)));

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

clone з новими значеннями - зручні «withers» для незмінних об'єктів, зокрема з readonly-властивостями:

public function withAmount(int $amount): static
{
    return clone($this, ['amount' => $amount]);
}

#[\NoDiscard] - PHP попередить, якщо результат функції проігноровано. Захищає від помилок на кшталт виклику методу незмінного об'єкта без присвоєння результату.

URI extension - вбудований розбір і нормалізація URL за RFC 3986 і стандартом WHATWG (Uri\Rfc3986\Uri, Uri\WhatWg\Url) замість неточного parse_url().

Інше:

  • array_first() і array_last() - перший і останній елемент без маніпуляцій з внутрішнім вказівником масиву.
  • Замикання й first-class callables у константних виразах (наприклад, у значеннях атрибутів і параметрів за замовчуванням).
  • Стек-трейси для фатальних помилок.
  • Постійні cURL share handles - повторне використання з'єднань і DNS-кешу між запитами.

Як оновлюватися: спершу прогнати тести й статичний аналіз на новій версії в CI, переглянути список застарілого в посібнику з міграції, і лише потім оновлювати прод.

Докладніше в документації: Реліз PHP 8.5

Типізовані константи класу (PHP 8.3) - тип можна вказати й для константи:

interface HasVersion
{
    const string VERSION = '1.0';
}

class Api implements HasVersion
{
    const string VERSION = '2.0';   // ок
    // const VERSION = 2;           // помилка: константа має бути string
}

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

#[\Override] - позначає метод, який має перевизначати метод батьківського класу чи інтерфейсу. Якщо такого методу в предка немає, PHP видасть помилку:

class BaseController
{
    protected function authorizeRequest(): void {}
}

class UserController extends BaseController
{
    #[\Override]
    protected function authorizeRequest(): void {}   // ок

    #[\Override]
    protected function authoriseRequest(): void {}   // помилка: опечатка, нічого не перевизначено
}

Навіщо #[\Override]:

  • Ловить опечатки в назві перевизначеного методу - без атрибута такий метод просто ніколи не викликається фреймворком.
  • Ловить зміни в батьківському класі: якщо бібліотека перейменувала чи видалила метод, усі «перевизначення» в нащадках одразу дадуть помилку замість тихого мертвого коду.
  • Документує намір для читача.

Ще з PHP 8.3: json_validate() (перевірка без розбору всього документа в пам'ять), динамічне звернення до констант класу (Foo::{$name}), повторна ініціалізація readonly-властивостей у __clone, нові методи Random\Randomizer, mb_str_pad().

Докладніше в документації: Реліз PHP 8.3