PHP 12432 ~ 10 мин.

Что нового в PHP 8.3

Что нового в PHP 8.3

PHP 8.3 был выпущен 23 ноября 2023 года. В нем есть улучшения классов только для чтения, новая функция json_validate(), дополнения к недавно добавленному классу Randomizer, обнаружение переполнения стека и многое другое.

Поправки для только для чтения rfc

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

readonly class Post
{
    public function __construct(
        public DateTime $createdAt,
    ) {}
    
    public function __clone()
    {
        $this->createdAt = new DateTime(); 
        // здесь это разрешено,
        // даже не смотря на то что свойство `createdAt` только для чтения.
    }
}

 

Типизированные константы класса rfc

Типизированные константы класса могут быть объявлены в классах, интерфейсах, трейтах и ​​перечислениях, вы можете указать типы констант класса так:

class Foo
{
    public const string A = 'a';
    public const int B = 1;
    public const float C = 1.1;
    public const bool D = true;
    public const array E = ['a', 'b']; 
} 

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

Атрибут #[Override] rfc

Новый атрибут #[Override] используется, чтобы показать намерение программиста: "Я знаю, что этот метод переопределяет родительский метод. Если это когда-либо изменится, сообщите мне".

Вот пример:

abstract class Parent
{
    public function methodWithDefaultImplementation(): int
    {
        return 1;
    }
}

final class Child extends Parent
{
    #[Override]
    public function methodWithDefaultImplementation(): void
    {
        return 2; // The overridden method
    }
} 

Теперь давайте представим, что в какой-то момент родительский метод меняет имя своего метода: 

abstract class Parent
{
    public function methodWithNewImplementation(): int
    {
        return 1;
    }
}

Благодаря этому атрибуту #[Override] PHP сможет определить, что он больше ничего не переопределяет, и выдаст ошибку.   

Отрицательные индексы в массивах нарушение

Если у вас есть пустой массив, и вы добавите элемент с отрицательным индексом, а затем добавите еще один элемент, этот второй элемент всегда будет начинаться с индекса 0:

$array = [];

$array[-5] = 'a';
$array[] = 'b';

var_export($array);

//array (
//  -5 => 'a',
//  0 => 'b',
//)

Начиная с PHP 8.3, следующий элемент будет добавлен в index -4:

//array (
//  -5 => 'a',
//  -4 => 'b',
//)

 

Анонимные классы только для чтения upd

Ранее нельзя было пометить анонимные классы как доступные только для чтения. Это исправлено в PHP 8.3:

$class = new readonly class {
    public function __construct(
        public string $foo = 'bar',
    ) {}
};


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

В PHP 8.3 добавлена ​​новая функция json_validate(), которая возвращает true или false в том случае, если заданная строка является допустимой строкой JSON. До PHP 8.3 единственным способом определить, является ли заданная строка допустимой строкой JSON, была попытка ее декодирования и проверка наличия каких-либо ошибок. Новая функция json_validate() использует тот же базовый синтаксический анализатор JSON, что и PHP, но потребует меньше памяти:


json_validate('[1, 2, 3]'); //true
json_validate('{1, 2, 3]'); //false


Динамический доступ к константам класса и Enum rfc

До PHP 8.3 синтаксис доступа к константам класса типа ClassName::{$varName}  был запрещен и приводил к синтаксической ошибке:


Parse error: syntax error, unexpected token ";", expecting "(" in ... on line ...

То же ограничение применялось и к Enum, где было невозможно получить элемент Enum динамически:


Parse error: syntax error, unexpected token "->", expecting "(" in ``` on line ```

Теперь PHP 8.3 и более поздние версии поддерживают динамическое получение констант класса и объектов Enum с именем переменной:


class MyClass {
    public const MY_CONST = 42;
}

$constName = 'MY_CONST';

echo MyClass::{$constName};

Функция gc_status() возвращает дополнительную информацию GC rfc

Функция gc_status() возвращает статистику сборщика мусора PHP и имеет четыре новых поля: running, protected, full и buffer_size: работает ли сборщик мусора, защищен ли сборщик мусора и размер буфера. Эта информация может быть полезна при отладке долго работающих PHP-приложений для обнаружения и оптимизации использования памяти.


var_dump(gc_status());

Новый метод \Random\Randomizer::getBytesFromString rfc

Класс \Random\Randomizer в PHP 8.3 поддерживает новый метод getBytesFromString, который возвращает последовательность случайных чисел запрошенной длины (параметр $length), содержащую только байты из запрошенной последовательности байтов (параметр $string).


namespace Random;  

class Randomizer {  
  // ...  
   public function getBytesFromString(string $string, int $length): string { }
 }

 

$rng = new Random\Randomizer();
$crockfordAlphabet = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';

$rng->getBytesFromString($crockfordAlphabet, 5); // "5YH8T"

Новые методы \Random\Randomizer::getFloat() и nextFloat() rfc

RFC добавляет новые методы в расширении Random, генерирующие случайное значение. \Random\Randomizer::getFloat()\Random\Randomizer::nextFloat(). Например если необходимо сгенерировать случайное число float между 0 <и < 10 и в диапазоне 0 <= и < 1:


$rng = new Random\Randomizer();
$rng->getFloat(0, 10, \Random\IntervalBoundary::OpenOpen); // 9.3835746900717

...

$rng = new Random\Randomizer();
$rng->nextFloat(); // 0.21185336351144


PHP CLI Lint (php -l) поддерживает проверку нескольких файлов одновременно

PHP CLI предоставляет функцию Linting, которая проверяет переданное имя файла на наличие синтаксических ошибок. Это полезно для быстрой проверки PHP-файла или куска кода перед выполнением:

php -l index.php
//No syntax errors detected in index.php


До PHP 8.3 было невозможно выполнить анализ нескольких файлов PHP за один вызов; независимо от количества предоставленных файлов, PHP CLI анализирует только первый файл. Начиная с PHP 8.3, можно передавать несколько файлов и PHP CLI проверяет их все за один вызов:

php -l index.php loader.php
// No syntax errors detected in index.php
// No syntax errors detected in loader.php

    

Более подходящие исключения даты/времени rfc break

Во многих случаях PHP просто выбрасывал объект Exception или Error или выдавал предупреждение/ошибку, когда что-то пошло не так при работе с датами и временем. Этот RFC добавляет для них соответствующие специальные исключения.

Теперь у нас есть исключения, такие как DateMalformedIntervalStringException, DateInvalidOperationException и DateRangeError.

Как правило, эти дополнения не нарушают код, поскольку эти недавно добавленные исключения и ошибки являются подклассами общего Exception/Error классов. Однако в этом RFC есть три небольших критических изменения:

  • Теперь Epoch doesn't fit in a PHP integer возвращает new DateRangeError вместо ValueError, который не является подклассом. Это проблема только для 32-битных платформ.
  • Предупреждение Only non-special relative time specifications are supported for subtraction становится новым DateTime::sub() date_sub() DateInvalidOperationException
  • Предупреждения Unknown or bad format (%s) at position %d (%c): %sи String '%s' contains non-relative elements, которые создаются при анализе неправильных/битых DateInterval строк, теперь будут выдавать новое исключение DateMalformedIntervalStringException при использовании с интерфейсом OO вместо отображения предупреждения и возврата false.


unserialize(): Вывод E_WARNING ошибок вместо E_NOTICE

До версии PHP 8.3 передача недопустимой строки в функцию unserialize() выдавала всего лишь уведомления PHP ( E_NOTICE) в определенных случаях, например, при синтаксических ошибках в сериализованной строке. Начиная с PHP 8.3 выдается предупреждение E_WARNING. Кроме того, некоторые условия ошибки так же изменились в функции serialize(), чтобы выдать E_WARNING:


unserialize("invalid-string");

 - PHP Notice:  unserialize(): Error at offset 0 of 14 bytes //было
 + PHP Warning:  unserialize(): Error at offset 0 of 14 bytes //стало

В идеале невозможность десериализации данной строки должна быть серьезной ошибкой и вызывать исключение. Однако для обеспечения обратной совместимости и упрощения путей обновления уровень ошибок в PHP 8.3 был увеличен, а в будущем возможно его обновление для создания исключений.

Трейты и статические свойства

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


Обнаружение переполнения стека pr

В PHP 8.3 добавлены две новые директивы ini с именами zend.max_allowed_stack_size и zend.reserved_stack_size. Приложения, близкие к переполнению стека вызовов, теперь могут вызывать Error при использовании больше, чем разница между zend.max_allowed_stack_size и zend.reserved_stack_size.

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

Значение по умолчанию для zend.max_allowed_stack_size равно 0, что означает, что PHP автоматически определит значение. Вы также можете указать -1, что ограничений нет или указать определенное количество байтов. Директива zend.reserved_stack_size используется для определения «буферной зоны», так что PHP может по-прежнему выдавать ошибку вместо того, чтобы фактически исчерпать память. Значение здесь должно быть числом байтов, но PHP сам определит для вас разумное значение по умолчанию, поэтому вам не обязательно устанавливать его, если только вы не сталкиваетесь с пограничными случаями для конкретных приложений.

И наконец, для файберов в качестве максимально допустимого размера стека используется существующая директива fiber.stack_size .

zend.max_allowed_stack_size=128K

 

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

В PHP различные строковые функции доступны в двух вариантах: один для байтовых строк, а другой для многобайтовых строк (mb). Однако заметным отсутствием среди многобайтовых строковых функций mbstring является эквивалент str_pad(). В функции str_pad() отсутствует поддержка многобайтовых символов, что вызывает проблемы при работе с языками, использующими многобайтовые кодировки, такие как UTF-8. Этот RFC предлагает добавить в PHP такую ​​функцию, которую мы будем называть mb_str_pad():

function mb_str_pad(
    string $string, 
    int $length, 
    string $pad_string = " ", 
    int $pad_type = STR_PAD_RIGHT, 
    ?string $encoding = null,
): string {}

// This will pad such that the string will become 10 bytes long.
var_dump(str_pad('Français', 10, '_', STR_PAD_RIGHT));   // BAD: string(10) "Français_"
var_dump(str_pad('Français', 10, '_', STR_PAD_LEFT));    // BAD: string(10) "_Français"
var_dump(str_pad('Français', 10, '_', STR_PAD_BOTH));    // BAD: string(10) "Français_"
 
// This will pad such that the string will become 10 characters long, and in this case 11 bytes.
var_dump(mb_str_pad('Français', 10, '_', STR_PAD_RIGHT));// GOOD: string(11) "Français__"
var_dump(mb_str_pad('Français', 10, '_', STR_PAD_LEFT)); // GOOD: string(11) "__Français"
var_dump(mb_str_pad('Français', 10, '_', STR_PAD_BOTH)); // GOOD: string(11) "_Français_"

Новая функция stream_context_set_options

В PHP есть функция stream_context_set_option, которая поддерживает две сигнатуры функций. Она может либо принимать массив параметров, которые можно установить для одного или нескольких контекстов или обёрток, либо принимать одно имя обёртки, имя параметра или его значение.

В рамках усилий PHP по удалению перегруженных сигнатур функций (функций, поддерживающих более одной сигнатуры), PHP 8.3 объявляет новую функцию stream_context_set_options (обратите внимание на последнюю букву "s" во множественном числе), которая поддерживает вторую сигнатуру выше.

Замыкания магических методов и именованные аргументы

Допустим, у вас есть класс, который поддерживает магические методы:

class Test {
    public function __call($name, $args) 
    {
        var_dump($name, $args);
    }
    
    public static function __callStatic($name, $args) {
        var_dump($name, $args);
    }
}

PHP 8.3 позволяет создавать замыкания из этих методов, а затем передавать этим замыканиям именованные аргументы. Раньше это было невозможно:

$test = new Test();

$closure = $test->magic(...);

$closure(a: 'hello', b: 'world'); 

Инвариантная видимость констант

Ранее видимость констант не проверялась при реализации интерфейса. В PHP 8.3 эта ошибка исправлена, но в некоторых местах она может привести к нарушению кода, если вы не знали об этом поведении: 

interface SomeInterface {
    public const FOO = 'foo';
}

class C implements SomeInterface {
    private const FOO = 'foo';
}

 

class_alias() поддерживает псевдонимы встроенных классов PHP

Функция class_alias создает псевдоним для предоставленного класса. Класс с псевдонимом ведет себя точно так же, как исходный класс.

Но до PHP 8.3 попытка создать псевдоним для встроенного класса PHP приводила к исключению ValueError:

class_alias('stdClass', 'MyClass'); 
class_alias('Traversable', 'NewTraversableInterface');

ValueError: class_alias(): Argument #1 ($class) must be a user-defined class name, internal class name given

Начиная с PHP 8.3 можно использовать псевдонимы для встроенных классов и интерфейсов и код отработает корректно:

class_alias('stdClass', 'MyClass'); 
class_alias('Traversable', 'NewTraversableInterface');

Функция class_alias() принимает bool $autoload = true в качестве третьего параметра. Этот параметр не влияет на встроенные классы, поскольку их не нужно загружать автоматически.

Небольшие устаревшие RFC

  • Не рекомендуется передавать отрицательное значение $width в mb_strimwidth()
  • Устареет и будет удалена константа NumberFormatter::TYPE_CURRENCY
  • Устареет и будет удалена неработающая реализация Mt19937 до PHP 7.1 (MT_RAND_PHP)
  • Устареет и будет удален вызов ldap_connect() с 2 параметрами $host и $port
  • Устаревшие остатки строковых вычисляемых утверждений кода

Небольшие, но заметные изменения

И как обычно, не каждое изменение в PHP проходит процесс RFC. На самом деле, большинство изменений включают обслуживание и исправление ошибок и не требуют RFC. Все эти изменения перечислены в документе ОБНОВЛЕНИЕ . Я перечислю некоторые из самых известных, но вам обязательно следует прочитать весь список, если вы хотите узнать о мельчайших деталях.

  • При использовании FFI функции C, которые имеют возвращаемый тип void теперь возвращают null вместо FFI\CData:void
  • posix_getrlimit() теперь принимает необязательный параметр $res, позволяющий получить ограничение на один ресурс.
  • mysqli_poll() теперь выдает ValueError, когда передаются аргументы чтения или ошибки.
  • array_pad() теперь ограничено только максимальным количеством элементов, которые может иметь массив. Раньше можно было добавить не более 1048576 элементов за раз.
  • Новые функции posix: posix_sysconf(), posix_pathconf(), posix_fpathconf() и posix_eaccess()
  • proc_get_status() многократное выполнение теперь всегда будет возвращать правильное значение в posix-системах.
  • директива opcache.consistency_checks в ini была удалена
  • Улучшены array_sum() и array_product()


Что думаешь?

Ниолай Петрозаводск30.11.2023

Классная обнова, ждал ее с рождения, НАЙС

Константин30.08.2023

Обычно обновляемся при улучшениях скорости, единственными заметными фичами здесь являются json_validate() и удаление лимита с array_pad().

Интересно что приведёт 8.4, вроде сегодня закатили новую разработку.

Категории
  • PHP 64
  • Заметки 15
  • Безопасность 3
  • Флуд 2
  • Nginx 2
  • ИТ новости 2
  • Видео 1
  • Docker 1
  • Roadmap 1
  • Архитектура 0

Хочешь поддержать сайт?

Делаем из мухи слона

sergeymukhin.com

персональный блог о веб-разработке от Сергея Мухина. Блог был основан в 2018 году, и собирался уделять основное внимание последним тенденциям, учебным пособиям, а также советам и рекомендациям, позволяющим начинающим девелоперам встать быстрее на правильную дорогу веб разработки, но что-то пошло не так 😃

Релизы PHP 8.4

Дата Релиз
8 Июня 2024 Альфа 1
20 Июня 2024 Альфа 2
04 Июля 2024 Альфа 3
16 Июля 2024 Feature freeze
18 Июля 2024 Бета 1
01 Августа 2024 Бета 2
15 Августа 2024 Бета 3
29 Августа 2024 RC 1
12 Сентября 2024 RC 2
26 Сентября 2024 RC 3
10 Октября 2024 RC 4
24 Октября 2024 RC 5
07 Ноября 2024 RC 6
21 Ноября 2024 GA

Что нового?