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

Реліз про «полірування» для команд на PHP 8.2.x: міцніші інваріанти (#[Override], типізовані константи), зручніший JSON і рядки (json_validate, str_increment/str_decrement), плюс довгий хвіст дрібних змін runtime, які проявляються під навантаженням або в рідких гілках коду.

Зміст


PHP 8.3 менше про одну «головну» фічу й більше про жорсткі контракти: можна задати типи констант, перевіряти override через #[\Override] і валідувати JSON без декодування — водночас рушій і стандартна бібліотека місцями суворіші (range(), proc_get_status(), винятки в Date/DOM). Закладіть час на QA навколо інкременту/декременту рядків (deprecated оператори, нові helper’и), reflection (ReflectionProperty::setValue) і налаштувань assert (deprecated INI та assert_options()).

#[\Override] — відсутні override на етапі компіляції

Позначайте методи, які мають перевизначати батька або інтерфейс. Якщо ім’я помилкове або метод прибрали з батька, PHP падає рано, замість того щоб тихо додати новий метод.

interface Logger
{
    public function log(string $message): void;
}

final class FileLogger implements Logger
{
    #[\Override]
    public function log(string $message): void
    {
        // ...
    }
}

Особливо корисно у великих кодових базах під час рефакторингу інтерфейсів.

Типізовані константи класу

Константи в класах, інтерфейсах, трейтах і enum можуть оголошувати типи — константи наближаються до решти системи типів.

interface Config
{
    public const string APP_NAME = 'MyApp';
}

Менше помилок «не той тип константи», які раніше спливали лише в місцях використання.

Readonly: анонімні класи й клонування

  • Анонімні класи можна оголосити readonly.
  • Readonly-властивості можна переініціалізувати під час clone, коли це дозволяє граф об’єктів — клони immutable-об’єктів стають менш болісними, ніж чисто на патернах 8.2.

Покращення мови (quality-of-life)

  • Динамічний доступ до константи класу: SomeClass::{$name} для імен констант під час виконання.
  • Ініціалізатори static-змінних можуть містити довільні вирази (не лише константи).
  • final для методів трейта під час імпорту методу з трейта.
  • Замикання з magic methods можуть приймати іменовані аргументи під час виклику.
  • php.ini: синтаксис fallback/default для чистішої конфігурації.

Нові функції (json_validate, str_*, DOM, Random тощо)

json_validate()

Перевірка JSON без декодування у значення PHP — зручно для API, черг і швидкої перевірки перед дорогим json_decode().

if (!json_validate($payload)) {
    throw new InvalidArgumentException('Invalid JSON');
}
$data = json_decode($payload, true, flags: JSON_THROW_ON_ERROR);

str_increment() / str_decrement()

Бажана заміна застарілим ++/-- для рядків (див. deprecations). Використовуйте для літерно-цифрових лічильників, де раніше покладалися на оператори інкременту.

$next = str_increment('a9'); // крок без рядкового ++
$prev = str_decrement($next);

DOM, Intl, Random, POSIX тощо

У PHP 8.3 додано багато методів DOM (наприклад insertAdjacentElement, getRootNode, replaceChildren), допоміжників Intl для календарів, методів Random у Randomizer (getFloat, nextFloat, …) і функцій POSIX (sysconf/pathconf/eaccess) — корисно для системних скриптів і tooling’у.

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

Стек / таймери / fibers

  • Глибока рекурсія біля межі стека може викинути Error при перевищенні zend.max_allowed_stack_size (мінус резерв); для fibers враховується fiber.stack_size.
  • Zend Max Execution Timers за замовчуванням увімкнені для ZTS-збірок на Linux — стежте за довгоживучими CLI-воркерами.

Процеси

  • proc_get_status() на POSIX повертає коректні значення при повторних викликах; результат може кешуватися (ключ "cached"). proc_close() після proc_get_status() тепер дає коректний код виходу (не -1).

Масиви й трейти

  • Видимість констант класу: при успадкуванні з інтерфейсів тепер перевіряється variance — код із м’якшою видимістю може потребувати виправлень.
  • Порожній масив + від’ємний перший індекс: наступний неявний ключ — n+1 (не 0).
  • Трейти зі static-властивостями: успадковані static у батька переоголошуються для кожного класу, що використовує трейт (окреме сховище) — може зачепити тонкий static-стан.

Стандартна бібліотека (високий ризик)

  • range(): суворіша валідація (TypeError/ValueError для поганих входів), більше попереджень на дивних межах, інша поведінка для символьних діапазонів, коли межі виглядають числовими — переперевірте код, де діапазони будуються з користувацького вводу.
  • number_format(): від’ємний $decimals тепер округлює до десяткової крапки (раніше ігнорувалося).
  • file(): некоректні комбінації прапорів відхиляються (наприклад FILE_APPEND раніше мовчки приймався).

Date / DOM / FFI / Opcache

  • Date: виразніші ієрархії DateError/DateException замість загальних попереджень/винятків — оновіть catch.
  • DOM: поведінка ближче до специфікації для вузлів без батька; виправлення createAttributeNS(); нові члени можуть конфліктувати з користувацькими підкласами — перевірте сумісність сигнатур.
  • FFI: void C-функції повертають null, а не фіктивний об’єкт FFI\CData:void.
  • Opcache: opcache.consistency_checks видалено (був несумісний із tracing JIT / кешем успадкування).

WeakMap

  • Самореферентні ключі в WeakMap можуть збиратися в циклах, де досяжність лише через ітерацію — перегляньте екзотичні кеші.

Deprecated (інкремент/декремент рядків, get_class(), assert INI)

Рядкові ++ / --

Інкремент/декремент для порожніх або нечислових рядків позначено deprecated; нечисловий інкремент — «м’який» deprecated. Для нового коду краще str_increment() / str_decrement().

get_class() / get_parent_class() без аргументів

Виклик без аргументів — deprecated — передавайте об’єкт або ім’я класу явно.

Assert

  • assert_options() і пов’язані константи — deprecated.
  • INI-налаштування assert.* — deprecated; міграція описана в розділі migration 8.3 про обробку INI.

Інше

  • Reflection: ReflectionProperty::setValue($value) (один аргумент) для static-властивостей deprecated — для static передайте null як об’єкт.
  • SQLite3: краще винятки; enableExceptions(false) дає deprecation.
  • Random: варіант MT_RAND_PHP — deprecated.

Інші зміни та експлуатація (gc_status, streams, highlights)

  • gc_status() повертає більше полів за часом (collector/destructor/free) — корисно під час налаштування пам’яті.
  • Streams: fread() на сокетах може повернути раніше за наявності даних у буфері; memory streams поводяться ближче до файлів при seek за кінець.
  • open_basedir: runtime ini_set відхиляє шляхи з .. навіть з префіксом ./.
  • highlight_string/file: змінилася структура HTML — оновіть знімки тестів, якщо порівнюєте підсвічування построчно.

Підсумок

PHP 8.3 вигідний тим, хто вважає константи й override частиною типового контракту: типізовані константи й #[\Override] зменшують «тихий дрейф» під час рефакторингу. Доповніть це json_validate для дешевої перевірки й чітким планом щодо рядкового інкременту та assert — саме там найчастіше дивується legacy-код.