PHP 8.1 уже обещает стать одним из лучших релизов

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

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

<?php

$array1 = [
    'Key A' => 1,
    'Key B' => 2,
];

$array2 = [
    'Key C' => 3,
    'Key D' => 4,
];

$array3 = [...$array1, ...$array2];
// Теперь в $array3 содержится: ['Key A' => 1, 'Key B' => 2, 'Key C' => 3, 'Key D' => 4]

Казалось бы, очень просто. Но обходиться так позволялось только с массивами с целочисленными ключами. При попытке проделать это с массивами со строковыми ключами возникала неустранимая ошибка fatal error.

Обратите внимание: эта новая функциональная возможность дает тот же результат, что и array_merge, которая используется с массивом со строковыми ключами в любой версии PHP, где она доступна.

RFC: https://wiki.php.net/rfc/array_unpacking_string_keys.

IntlDatePatternGenerator

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

Если вкратце, цель этого класса  —  определить, какой формат больше всего подойдет той или иной локали. Проиллюстрируем это примером, приведенным в RFC (рабочем предложении):

<?php

$skeleton = "YYYYMMdd";
 
$today = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-04-24');
 
$dtpg = new \IntlDatePatternGenerator("de_DE");
$pattern = $dtpg->getBestPattern($skeleton);
echo "de: ", \IntlDateFormatter::formatObject($today, $pattern, "de_DE"), "\n";
 
$dtpg = new \IntlDatePatternGenerator("en_US");
$pattern = $dtpg->getBestPattern($skeleton), "\n";
echo "en: ", \IntlDateFormatter::formatObject($today, $pattern, "en_US"), "\n";
 
/*
de: 24.04.2021
en: 04/24/2021
*/

Видите? Теперь у нас будет гораздо меньше головной боли при работе с форматами дат и локализацией. Дайте вашей локали getBestPattern и «скелет» для форматирования. После этого, вызвав IntlDateFormatter, вы получите отформатированную дату для локали. Мне это очень нравится.

RFC: https://wiki.php.net/rfc/intldatetimepatterngenerator.

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

Стоит напомнить, что перечисление позволяет определить набор констант, значение которых не важно. Важно здесь то, что эти константы строго типизированы. Если атрибуту или аргументу метода требуется значение из перечисления, ничего другого передавать нельзя. Вот фрагмент кода, в котором показано это поведение:

<?php

enum Foo
{
    case BAR;
    case BAZ;
}

public function method(Foo $foo): void
{
    // ...
}

method(Foo::BAR); // Работает хорошо!
method('BAR');    // Неустранимая ошибка, потому что у «BAR» тип, отличный от типа Foo

Там, где задействуются многочисленные константы и их значения не важны, используются перечисления. Когда значения важны, PHP одновременно вводит резервное перечисление, позволяющее определить значения для константы (и сохранить преимущества строгой типизации!). Таким образом вы уверены в том, что кто бы ни использовал / ни занимался поддержкой кода, эти значения ограничены определенным набором.

RFC: https://wiki.php.net/rfc/enumerations.

Чистые пересечения типов

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

<?php

interface A {}
interface B {}

class C implements A, B {}
class D implements A {}

class Test
{
    public A&B $property;
}

$test = new Test();

$test->property = new C(); // Работает хорошо!
$test->property = new D(); // Запрещено, D не реализует A и B

Объясняется это в рабочем предложении так: хотя такого рода проверка уже возможна в PHP, ее проведение подразумевает использование промежуточного интерфейса. Это намного оптимальнее и удобнее для восприятия человеком.

RFC: https://wiki.php.net/rfc/pure-intersection-types.

Файберы

Файберы  —  это блоки кода, которые запускаются, приостанавливаются, возобновляются и прерываются основным кодом. У них есть свое состояние и переменные.

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

В PHP происходит следующее: время от времени вместо основного блока выполняется код файбера, после чего выполнение возвращается к основному блоку. При этом нет гарантии, что файбер будет выполнен в какой-то точно определенный момент времени.

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

В какие-то моменты происходит переключение с основного блока кода на блок кода файбера. В файбере выполняется метод, который получает и выводит на экран число подсчитанных на данный момент элементов. Затем выполнение возвращается к основному блоку кода, который подсчитывает элементы.

RFC: https://wiki.php.net/rfc/fibers.

Тип «never» для возвращаемых значений

Тип «never» не имеет аналогов среди типов значений, возвращаемых методами. Это ключевое слово показывает, что метод никогда ничего не вернет. Причем не важно, явно указан тип «never» или неявно. Другими словами, метод никогда не доберется до своей заключительной скобки.

Как это возможно на практике? На практике метод просто должен выбросить исключение, вызвать die или exit. Кроме того, never нельзя задействовать в типах объединения, например так: never|string.

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

<?php

class MyClass
{
    //...
    
    public function myMethod(): void
    {
        try {
            $response = $this->client->request('http://localhost/exception');
        } catch (\Exception $exception) {
            $this->handleError($exception);
        }
        
        // ...
    }
    
    private function handleError(\Exception $thrown): never
    {
        // Выполняются все типы операций до заведомого неуспеха, после чего выбрасывается исключение
        $this->logger->critical($thrown->getMessage());
        $this->errorNotifier->warn();
        // и т. д.
        
        throw $thrown; // Метод *всегда* заканчивается выбрасыванием исключения, вызовом «die()» или «exit()»
    }
}

RFC: https://wiki.php.net/rfc/noreturn_type.

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

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Alexandre Daubois: PHP 8.1 is coming  —  and it already promises to be one of the best releases

Предыдущая статьяПрименение Let’s Encrypt для автоматизации HTTPS в кластерах Kubernetes на Raspberry Pi
Следующая статьяИнтерфейсы с вкладками без JavaScript