Что нового в PHP 8.1

Что нового в PHP 8.1

что обещает нам новый выпуск

PHP 8.1 в настоящее время находится в активной разработке и, вероятно, будет выпущен где-то в конце ноября 2021 года

Но мы уже знаем некоторые функции, изменения и устаревшие версии, поэтому давайте рассмотрим их уже сейчас. Имейте в виду, что этот список как и PHP 8 будет расти с годами.

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

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

Распаковка массива с помощью строковых ключей rfc

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


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

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

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

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

Новый тип возврата never rfc 

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

function redirect(string $url): never {
header('Location: ' . $url);
exit();
}

redirect('Test'); // код гарантирует не продолжение.
do_something_else();

Тип возвращаемого значения  never аналогичен существующему типу возвращаемого значения void, но тип never гарантирует, что программа завершится или выдаст исключение. Другими словами, объявленная функция/метод never типом вообще не должна вызывать return. 


function foo(): never {
return;
}
foo();


TypeError: dispatch(): Nothing was expected to be returned

Как видите, если функция/метод с типом never никак не сгенерирует исключение, или прекратит  работу, то PHP выдаст исключение TypeError.

А если при never типе вызвать return, то PHP выдаст Fatal Error. Узнать об этом можно будет только во время вызова, а не во время синтаксического анализа.


function foo(): never {
return;
}
foo();

 

Fatal error: A never function must not return in ... on line 2

Исходный RFC предлагал использовать noreturn для этой цели. Впрочем последующее голосование в RFC  прошло уже в пользу never и он был избран.

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

Возможно, время от времени, вам приходится иметь с этим дело: определять, находятся ли ключи массива в числовом порядке, начиная с индекса 0. Точно так же, как 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

Любой массив с ключами, не начинающимися с нуля, или любой массив, в котором не все ключи являются целыми числами в последовательном порядке, результат будет false:


// ключи начинаются не с 0
array_is_list([1 => 'apple', 'orange']); // false

// Ключи не отсортированы
array_is_list([1 => 'apple', 0 => 'orange']); // false

// Не все числовые ключи
array_is_list([0 => 'apple', 'foo' => 'bar']); false

// Непоследовательные ключи
array_is_list([0 => 'apple', 2 => 'bar']); false
  • array_is_list принимает только параметры типа array. Передача любого другого типа вызовет исключение TypeError.
  • array_is_list не принимает iterable или другие объекты класса, подобные массиву, такие как ArrayAccess, SPLFixedArray и т.д.
  • array_is_list объявлен в глобальном пространстве имен.  

Полифил функции будет выглядеть, как:


function array_is_list(array $array): bool {
if (empty($array)) {
return true;
}

$current_key = 0;
foreach ($array as $key => $noop) {
if ($key !== $current_key) {
return false;
}
++$current_key;
}

return true;
}

 

Явное восьмеричное целочисленное буквальное обозначение rfc

Теперь вы можете использовать 0o (нуль и маленькая буква o) и 0O (нуль и большая буква O) для обозначения восьмеричных чисел. Предыдущее обозначение с префиксом числа "0" по-прежнему работает:


016 === 0o16; // true
016 === 0O16; // true

Enums (Перечисления) rfc

Перечисления будут добавлены в PHP 8.1.

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


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

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


class Order
{
public function __construct(
private Status $status = Status::Pending;
) {}

public function setStatus(Status $status): void
{
// …
}
}

$order->setStatus(Status::Active);

Fibers rfc

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

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


$fiber = new Fiber(function (): void {
$valueAfterResuming = Fiber::suspend('after suspending');

// …
});

$valueAfterSuspending = $fiber->start();

$fiber->resume('after resuming');

 

Улучшения производительности pr

Дмитрий Стогов добавил некоторые улучшения в opcache, он называет это "кешем наследования". Эта функция позволяет кэшировать ссылки между классами, так же как связанные классы могут быть предварительно загружены в PHP 7.4.

Дмитрий сообщает о приросте производительности от 5% до 8% благодаря этому изменению, приятная небольшая деталь, на которую следует обратить внимание в PHP 8.1.


Критические изменения

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

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

Небольшое изменение способа использования $GLOBALS  существенно повлияет на производительность всех операций с массивами. Никита Попов отлично справляется с объяснением проблемы и решения в RFC . Это изменение означает, что в некоторых крайних случаях работать с $GLOBAL больше нельзя.

«То, что больше не поддерживается, - это запись в $GLOBALS, взятую как единое целое».

Все нижеперечисленное вызовет ошибку времени компиляции:


$GLOBALS = [];
$GLOBALS += [];
$GLOBALS =& $x;
$x =& $GLOBALS;
unset($GLOBALS);

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


by_ref($GLOBALS); // Run-time error

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

Перенос Ресурсов в объекты

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

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

Функции IMAP с объектами IMAPConnection. Как и при изменении информации о файле, IMAP работает как imap_body, а imap_open больше не работает с ресурсами.

Устарела передача null не null-ых аргументов внутренним функциям rfc

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


str_contains("string", null);

 В PHP 8.1 такие ошибки будут вызывать предупреждение об устаревании, в PHP 9 они будут преобразованы в ошибки типа.


Другие небольшие изменения

Вот краткое изложение наиболее значительных изменений:


  • MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH больше не действует
  • MYSQLI_STORE_RESULT_COPY_DATA больше не действует
  • PDO::ATTR_STRINGIFY_FETCHES теперь также работает с логическими значениями
  • Целые числа и числа с плавающей запятой в наборах результатов PDO MySQL и Sqlite будут возвращаться с использованием собственных типов PHP вместо строк при использовании эмулированных подготовленных операторов.
  • Такие функции, как htmlspecialchars и htmlentities  по умолчанию, также переходят 'в '; неверно сформированный UTF-8 также будет заменен символом Юникода вместо того, чтобы приводить к пустой строке
  • У hash, hash_file и hash_init есть дополнительный аргумент  $options, по умолчанию он имеет значение [], поэтому не повлияет на ваш код.
  • Новая поддержка для MurmurHash3 и xxHash



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


Сергей Мухин

Веб-разработчик со стажем программирования более 6 лет, постоянно учусь, люблю делать новые проекты.

Есть вопросы?

Я почти всегда в режиме онлайн

Связаться со мной