Версия PHP 8.1 находится в активной разработке и будет выпущена 25 ноября 2021 г. Следует иметь в виду, что эта дата может измениться, если основная команда разработчиков решит, например, добавить дополнительный бета-выпуск. Мы уже знаем о новых возможностях, повышении производительности, изменениях и упразднении сомнительной функциональности. Давайте рассмотрим эти новшества по порядку.

Новые возможности

Как и в каждом выпуске, в PHP 8.1 добавлено несколько новых полезных возможностей. Имейте в виду, что в течение года этот список будет пополняться.

Перечисления rfc

В PHP 8.1 будут добавлены перечисления (enum)! Если вы не уверены, зачем они нужны, можете прочитать о них здесь.

Добавление перечислений будет значительным улучшением PHP — я, например, с нетерпением жду их появления в PHP 8.1. Вот пример того, как они будут выглядеть:

enum Status {
  case Pending;
  case Active;
  case Archived;
}

И вот как они будут использоваться:

Более подробно о том, как можно использовать перечисления, вы можете узнать из уже упомянутой статьи.

Файберы rfc

Файберы (fiber), или «зеленые потоки», представляют собой низкоуровневый механизм управления параллелизмом. Возможно, вам не придется использовать их в своих приложениях напрямую, но они будут широко применяться такими фреймворками, как Amphp и ReactPHP.

Вот простой пример использования файберов:

$fiber = new Fiber(function (): void {
    $valueAfterResuming = Fiber::suspend('после приостановки');

    // … 

});

$valueAfterSuspending = $fiber->start();

$fiber->resume('после возобновления');

Если вы хотите узнать больше о файберах и о том, что они могут и чего не могут делать, прочтите эту статью.

Повышение производительности pr

Дмитрий Стогов добавил в opcache ряд улучшений, назвав их кешем наследования (inheritance cache). Эта возможность позволяет кешировать связи между классами и очень похожа на предзагрузку связанных классов в PHP 7.4.

Дмитрий сообщает, что в результате производительность повышается на 5–8 %, — одна из приятных мелочей, ожидаемых от PHP 8.1.

Распаковка массивов со строковыми ключами rfc

Распаковка массивов была доступна еще в PHP 7.4, но работала только с числовыми ключами. Строковые ключи не поддерживались, так как не было единого мнения относительно объединения дубликатов в массивах. В данном RFC эта проблема четко решается путем следования семантике array_merge:

$array1 = ["a" => 1];

$array2 = ["b" => 2];

$array = ["a" => 0, ...$array1, ...$array2];

var_dump($array); // ["a" => 1, "b" => 2]

Новый тип never rfc

Тип never можно использовать для указания того, что функция будет останавливать поток выполнения программы. Это можно сделать вызовом исключения или функции exit либо подобных ей.

function dd(mixed $input): never
{
    // dump

    exit;
}

never отличается от void тем, что void позволяет программе продолжить выполнение. Этот тип может показаться необычным новшеством, но на деле он будет весьма полезен для статических анализаторов.

Новая функция array_is_list  rfc

Возможно, вы имели дело с задачами, когда нужно было определить, представляют ли ключи массива числовую последовательность 0, 1, 2, 3..., подобно тому, как функция json_encode определяет, следует ли кодировать массив как массив или как объект.

В PHP 8.1 добавлена встроенная функция для определения того, является ли массив списком с такой семантикой или нет:

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

Финальные константы классов rfc

Константы классов в PHP могут быть переопределены при наследовании:

class Foo
{
    public const X = "foo";
}

class Bar extends Foo
{
    public const X = "bar";
}

Начиная с PHP 8.1 такие константы можно помечать словом final, чтобы исключить эту возможность:

class Foo
{
    final public const X = "foo";
} 

class Bar extends Foo
{
    public const X = "bar";
    Fatal error: Bar::X cannot override final constant Foo::X
}

Новая функция fsync rfc

В PHP 8.1 добавлены функции fsync и fdatasync, выполняющие перед возвратом принудительную синхронизацию изменений файла с диском и обеспечивающие очистку буферов записи операционной системы.

$file = fopen("sample.txt", "w");

fwrite($file, "Какое-то содержимое");

if (fsync($file)) {
    echo "Файл успешно сохранен на диск.";
}

fclose($file);

Поскольку синхронизация c диском — это операция файловой системы, функция fsync будет работать только с обычными файловыми потоками. При попытке синхронизации нефайловых потоков будет выдаваться предупреждение.

Явная нотация восьмеричных целочисленных литералов rfc

Теперь для обозначения восьмеричных чисел можно использовать префиксы 0o и 0O. Ранее принятая нотация, согласно которой к числу следовало добавлять префикс 0, также по-прежнему будет работать.

016 === 0o16; // true

016 === 0O16; // true

Изменения, которые могут затронуть существующий код

Хотя PHP 8.1 является младшей версией, она упраздняет некоторую сомнительную функциональность, а также вносит изменения, которые технически могут испортить уже существующий код. Давайте поговорим об этих нововведениях.

Ограничение использования $GLOBALS rfc

Небольшое изменение условий работы с массивом $GLOBALS существенно повлияет на производительность всех операций с массивами. Никита Попов отлично объяснил проблему и ее решение в соответствующем RFC. Суть изменения в том, что с массивом $GLOBALS теперь нельзя будет выполнять некоторые редко используемые операции. «Перезапись $GLOBALS как единого целого отныне не поддерживается. Все приведенные ниже инструкции вызовут ошибку во время компиляции»:

$GLOBALS = [];

$GLOBALS += [];

$GLOBALS =& $x;

$x =& $GLOBALS;

unset($GLOBALS);

Кроме того, передача $GLOBALS по ссылке будет вызывать ошибку времени выполнения:

by_ref($GLOBALS); // Ошибка времени выполнения

Никита проанализировал 2000 самых популярных пакетов на Packagist и обнаружил только 23 случая, на которые повлияет это изменение. Можно сделать вывод, что влияние этого формально критического изменения будет незначительным, поэтому было решено добавить его в PHP 8.1. Следует отметить, что большая часть разработчиков от этого только выиграет, поскольку оно положительно повлияет на производительность кода.

Переход от ресурсов к объектам

Эти изменения являются частью долгосрочной стратегии преобразования всех ресурсов в выделенные объекты. Подробнее об этом можно прочитать здесь.

Функции Fileinfo и объекты finfo

Такие функции, как finfo_file и finfo_open, ранее принимали и возвращали ресурсы. Начиная с PHP 8.1 они работают с объектами finfo.

Функции IMAP и объекты IMAPConnection

Как и в случае функций Fileinfo, функции IMAP, такие как imap_body и imap_open, больше не работают с ресурсами.


Запрещена передача null в не поддерживающие null аргументы внутренних функций rfc

Суть изменения проста: внутренние функции в настоящее время принимают null в качестве аргументов, которые не могут иметь значение null, а данный RFC запрещает такое поведение. Например, сейчас возможен такой вызов:

str_contains("string", null);

В PHP 8.1 при вызовах такого рода будет выдаваться предупреждение об их упразднении (deprecation), а в PHP 9 эти предупреждения станут ошибками типизации.

Мелкие изменения

С каждым выпуском в язык вносится множество небольших изменений. Все они перечислены в руководстве UPGRADING на GitHub — обязательно ознакомьтесь с ним, если хотите знать о таких мелочах.

Вот сводка наиболее существенных изменений:

  • MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH больше не работает.

  • MYSQLI_STORE_RESULT_COPY_DATA больше не работает.

  • PDO::ATTR_STRINGIFY_FETCHES теперь работает и с логическим типом данных (boolean).

  • При использовании эмулированных подготовленных операторов целые числа и числа с плавающей запятой в наборах результатов PDO MySQL и SQLite будут возвращаться с использованием собственных типов PHP вместо строк.

  • Такие функции, как htmlspecialchars и htmlentities, теперь будут по умолчанию преобразовывать символ ' в '; некорректные данные в кодировке UTF-8 также будут заменяться символом Юникода, а не пустой строкой.

  • В функции hash, hash_file и hash_init добавлен новый аргумент $options; по умолчанию он имеет значение [], так что это не повлияет на уже написанный код.

  • Добавлена поддержка MurmurHash3 и xxHash.

На этом пока все. Я собираюсь регулярно обновлять эту статью в течение года, поэтому оформите подписку, если хотите быть в курсе. Вы рады скорому выходу PHP 8.1? Поделитесь своими ожиданиями со мной в Twitter!


Материал подготовлен в рамках курса "PHP Developer. Professional".

Всех желающих приглашаем на интенсив "Поговорим о тестировании" (День 2). На этом занятии мы:
— Поговорим про тестируемый код и о том как его писать;
— Освоим написание Unit-тестов с использованием PHPUnit;
— A-TRIP, TDD и Red-Green-Refactor;
— Посмотрим на идеологию CI/CD и запуск автоматического прогона наших тестов в Travis.
К концу занятия научимся писать правильные Unit-тесты. РЕГИСТРАЦИЯ

Комментарии (6)


  1. tempick
    14.07.2021 16:56
    +1

    И вот как они будут использоваться:
    Кажется, зыбыли добавить примеры


  1. axp
    15.07.2021 10:42

    ...будет вызывать ошибку времени выполнения

    Три раза сломал глаза, прежде чем понял, что речь о RuntimeException


  1. juunitaki
    15.07.2021 18:10

    Когда же сделают перегрузку операторов? Был вот такой RFC, но как я понял, его отклонили.


    1. Acuna
      21.07.2021 01:45

      Если я правильно понял, это чтобы в выражениях перегружать отдельные операторы? Понятно что может понадобиться, отрицать не буду, но неужели настолько часто, что вы этого так ждете? Не смог сходу даже реальных кейсов придумать когда имеется готовое условие, а в нем нужно плюс на минус заменить не меняя остальных частей. Почему это нужно, прошлый разраб ошибку сделал, еще и в формуле? Но из таких ошибок что, весь проект состоит что его приходится так рефакторить? Или я что-то не так понял?


      1. juunitaki
        21.07.2021 01:58

        В C++ есть. Можно определить + для комплексных чисел, кватернионов, векторов, матриц и так далее. Например, можно было бы использовать в https://carbon.nesbot.com/docs/#api-addsub


        1. Acuna
          21.07.2021 16:40

          А, ну для дат это полезно, да, и даже применимо, для остального честно признаться все-таки язык не для этого, вот был бы он компилируемым и для дестопа - тогда конечно, мне он и самому нравится, но ведь он только для веба, увы( Но и вроде это нужно на уровне парсера реализовывать если я правильно понял, но можно все неслабо так поломать, я думаю они так и порешили, ибо для веба слишком возни много.