PHP 8.5: Головні нововведення

PHP 8.5 продовжує лінію «більше виразності в мові»: оператор конвеєра (|>), #[\NoDiscard] проти ігнорування повернених значень і замикання в константних виразах для атрибутів і значень за замовчуванням. На рівні платформи — завжди увімкнене URI-розширення, суворіший filter і суттєві зміни PDO / Opcache — закладайте час на QA не лише для синтаксису, а й для розширень, збірки та INI.

Зміст


Оператор конвеєра (|>)

Оператор pipe передає значення зліва в callable з одним параметром справа. Зручний для ланцюгів перетворень без тимчасових змінних.

$result = 'Hello World' |> strlen(...);
// Те саме: $result = strlen('Hello World');

Правила, які “кусаються”: праворуч має бути callable рівно з одним параметром (і не by-ref). Якщо праворуч не вийде валідний callable — буде Error. Arrow functions у парі з |> потрібно брати в дужки через синтаксичну неоднозначність. Деталі — у functional operators.

Замикання та first-class callable у константних виразах

У PHP 8.5 замикання та first-class callable дозволені в константних виразах, зокрема:

  • аргументи атрибутів;
  • значення за замовчуванням для властивостей і параметрів;
  • константи та константи класу.

Практично це зручно, коли метадані/дефолти мають посилатися на реальний callable, а не на “магічні” рядки.

#[\NoDiscard] і приведення (void)

#[\NoDiscard] позначає функції/методи, чиє повернене значення небажано ігнорувати.

(void) явно означає «відкидаю навмисно». Само по собі не змінює runtime, але може приглушити попередження, пов’язані з #[\NoDiscard], і допомагає статичному аналізу.

#[\NoDiscard]
function loadConfig(): array { return []; }

(void) loadConfig();

Практичний підхід: позначайте результати, які легко “забути” використати (builder-и, валідатори, методи, що повертають bool/Result), щоб виклики без перевірки не проходили непоміченими.

Розширення URI (RFC 3986 / WHATWG URL)

У PHP 8.5 додано завжди увімкнене розширення uri для URI/URL за RFC 3986 і моделлю WHATWG URL. Корисно для коректного парсингу замість ручного substr на користувацькому вводі.

Оновлення бібліотек і розширень

  • Filter: прапор FILTER_THROW_ON_FAILURE — при помилці валідації можна отримати виняток замість false (не поєднується з FILTER_NULL_ON_FAILURE).
  • Intl: наприклад IntlListFormatter, Locale::addLikelySubtags() / minimizeSubtags(), додаткові константи стилів NumberFormatter для валют (залежить від ICU).
  • Session / cookies: session_set_cookie_params(), session_get_cookie_params(), session_start(), setcookie() / setrawcookie() — підтримка partitioned cookies через ключ "partitioned".
  • Standard: mail() з sendmail повертає реальні помилки; getimagesize() — HEIF/HEIC, SVG (за наявності libxml), додаткові поля одиниць вимірювання розмірів.
  • DOM: наприклад Dom\Element::$outerHTML, властивість $children у Dom\ParentNode.
  • cURL: нові ключі/опції для curl_getinfo / curl_setopt (часто залежать від версії libcurl).

Нові функції (array_first, array_last, обробники, …)

  • Core: get_error_handler(), get_exception_handler(), Closure::getCurrent()
  • Standard: array_first(), array_last()
  • Reflection, Opcache, драйвери — див. new functions

Практичні рецепти

Pipe-ланцюжок для нормалізації

$slug = $raw
    |> trim(...)
    |> strtolower(...)
    |> preg_replace('/\s+/', '-', ...);

Filter з винятком замість false

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, FILTER_THROW_ON_FAILURE);

Перший/останній елемент без ручної індексації

$first = array_first($list);
$last  = array_last($list);

Partitioned cookies (де це доречно)

setcookie('sid', $sid, [
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'None',
    'partitioned' => true,
]);

Зворотно несумісні зміни (міграційні нотатки)

Ядро мови / runtime

  • class_alias(): заборонені імена "array" та "callable".
  • Нестроге порівняння з bool для «непорівнюваних» об’єктів — уніфіковано з (bool)$object.
  • gc_collect_cycles(): повернене значення більше не враховує рядки/ресурси, зібрані опосередковано.
  • Final-підкласи: гнучкіше заміщення static на self або конкретний клас.
  • Tick handlers: після shutdown, деструкторів і output handlers.
  • Трейти: змінено порядок прив’язки відносно батька.
  • Помилки компіляції/лінкування: інший порядок обробки.
  • #[\Attribute] на abstract class, enum, interface або trait: помилка компіляції, якщо не відкладена валідація через #[\DelayedTargetValidation].
  • INI disable_classes: видалено.
  • Деструктуризація не-масиву й не-null через []/list(): попередження.
  • Приведення до int поза діапазоном і NAN: попередження.

Opcache

  • Opcache завжди вбудований у бінарник; zend_extension=opcache.so / .dll дає попередження. Оновіть документацію deployment.

PDO (високий ризик)

  • Змінені числові значення PDO::FETCH_* для ряду прапорів.
  • Аргументи конструктора для FETCH_CLASS: семантика як у call_user_func_array.
  • Обмеження на FETCH_PROPS_LATE, FETCH_INTO з fetchAll() тощо.

DOM / SPL / інше

  • Клонування живих NodeList / NamedNodeMapпомилка.
  • ArrayObject: не приймає enum як елементи.
  • mysqli: повторний виклик конструктора на вже створеному об’єкті → Error.
  • У багатьох розширеннях з’являються ValueError там, де раніше були TypeError/warnings або тихе падіння (Bzip2 діапазони в bzcompress(), LDAP invalid option, SNMP host/port, sockets порти, FileInfo nul bytes тощо) — перевіряйте “користувацькі входи” тестами.

Deprecated (чеклист)

Це “що краще почистити завчасно”, перш ніж стане hard error у наступних версіях. Повний список: migration85 deprecated.

Core

  • Вивід усередині user output handler — deprecated (повідомлення обходить handler, щоб бути видимим).
  • Неканонічні назви кастів (boolean), (integer), (double), (binary) → використовуйте (bool), (int), (float), (string).
  • case із ; замість : — deprecated.
  • Backticks як alias для shell_exec — deprecated.
  • __debugInfo() повертає null — deprecated → повертайте [].
  • report_memleaks INI — deprecated.
  • Redeclare констант — deprecated (і надалі warning).
  • “Проблеми binding-у closure” (binding instance до static closure, unbind $this, rebind scope до internal класу тощо) — deprecated.
  • __sleep() / __wakeup() — soft-deprecated → переходьте на __serialize() / __unserialize().
  • null як array offset або в array_key_exists() — deprecated.
  • Інкремент нечислових рядків — deprecated → використовуйте str_increment().
  • Derivation $_SERVER['argc']/argv із query string для не-CLI SAPIs — deprecated (register_argc_argv).

Extensions / standard library

  • cURL: curl_close() і curl_share_close() deprecated (handles звільняються автоматично).
  • FileInfo: finfo_close() deprecated; $context у finfo_buffer() deprecated.
  • GD: imagedestroy() deprecated.
  • XML: xml_parser_free() deprecated.

PDO

  • uri: DSN — deprecated (ризики при remote URIs).
  • Driver-specific константи/методи в базовому PDO — deprecated → використовуйте Pdo\\* класи (Pdo\\Mysql::..., Pdo\\Pgsql::..., тощо).

Інші зміни та експлуатація

  • CLI: --ini=diff; cli_set_process_title() падає, якщо заголовок занадто довгий (без тихого обрізання).
  • FPM: fastcgi.script_path_encoded для керування decoding script path при ProxyPass; access log limit враховує log_limit.
  • Core: hrtime() на macOS використовує рекомендований API.
  • INI: fatal_error_backtraces, max_memory_limit, обмеження на memory_limit у runtime.
  • Opcache: opcache.file_cache_read_only, налаштування JIT, коректне повідомлення про пам’ять.
  • Продуктивність: швидше створення винятків, колбеки по масивах, Reflection, SIMD, TAILCALL VM з Clang ≥ 19 — other changes.

Підсумок

PHP 8.5 поєднує зручніший синтаксис і суворішу платформу. Після оновлення перевірте режими PDO, cookie/session, код із застарілими close-хелперами та старе нестроге порівняння об’єктів із bool.