PHP 8.3: Главные нововведения
Выпуск про «полировку» для команд на PHP 8.2.x: сильнее инварианты (#[Override], типизированные константы), удобнее JSON и строки (json_validate, str_increment/str_decrement), плюс длинный хвост мелких изменений runtime, которые проявляются под нагрузкой или в редких ветках кода.
Содержание (Оглавление)
#[\Override]— ловим отсутствующие override на этапе компиляции- Типизированные константы класса
- Readonly: анонимные классы и клонирование
- Улучшения языка (quality-of-life)
- Новые функции (
json_validate,str_*, DOM, Random и др.) - Обратно несовместимые изменения (миграционные заметки)
- Deprecated (инкремент/декремент строк,
get_class(), assert INI) - Прочие изменения и эксплуатация (gc_status, streams, highlights)
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), helper’ов 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:
voidC-функции возвращают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_PHPdeprecated.
Прочие изменения и эксплуатация (gc_status, streams, highlights)
gc_status()отдаёт больше полей по времени (collector/destructor/free) — полезно при настройке памяти.- Streams:
fread()на сокетах может вернуть раньше при наличии данных в буфере; memory streams ведут себя ближе к файлам при seek за конец. open_basedir: runtimeini_setотклоняет пути с..даже с префиксом./.- highlight_string/file: изменилась структура HTML — обновите снапшоты тестов, если подсветку сравниваете построчно.
Итог
PHP 8.3 выгоден тем, кто считает константы и override частью типового контракта: типизированные константы и #[\Override] уменьшают «тихий дрейф» при рефакторинге. Дополните это json_validate для дешёвой проверкой и явным планом по строковому инкременту и assert — именно там чаще всего удивляется legacy-код.