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 още при компилация

Маркирайте методи, които трябва да 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'); // стъпка без string ++
$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 build-ове на Linux — внимавайте с дълго живеещи CLI worker-и.

Процеси

  • proc_get_status() на POSIX връща коректни стойности при повторни извиквания; резултатът може да се кешира (ключ "cached"). proc_close() след proc_get_status() вече дава коректен exit code (не -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 структурата — обновете snapshot тестове, ако сравнявате подсветката.

Обобщение

PHP 8.3 помага на екипи, които третират константите и override като част от типовия договор: типизираните константи и #[\Override] намаляват „тихия дрейф“ при рефакторинг. Комбинирайте с json_validate за евтина валидация и ясен план за низов инкремент и assert — там legacy кодът най-често се изненадва.