- PVSM.RU - https://www.pvsm.ru -

Вместе с PHP-разработчиками Александром Макаровым (@SamDark [1]), Валентином Удальцовым (@vudaltsov [2]) и наставником Хекслета по PHP Владленом Гилязетдиновым (@funkylen [3]) разбираемся, какие новые фичи появились в PHP 8.2, насколько эти изменения глобальны и какую роль в них сыграл проект РHP Foundation.
Эта статья — саммари стрима YouTube-канала PHP Point.
Кстати, ежегодный опрос [4] русскоязычного PHP-сообщества с итогами года запущен! Результатами поделимся в конце января.

Поля readonly сделали еще до версии 8.2. Раньше писать в них код и читать его можно было только в конструкторе. А теперь для этого не нужно помечать каждое поле — достаточно отметить весь класс [5] как readonly.
Как выглядел код в предыдущих версиях PHP:
class BlogData
{
public readonly string $title;
public readonly Status $status;
public function __construct(string $title, Status $status)
{
$this->title = $title;
$this->status = $status;
}
}
Как выглядит код в PHP 8.2:
readonly class BlogData
{
public string $title;
public Status $status;
public function __construct(string $title, Status $status)
{
$this->title = $title;
$this->status = $status;
}
}
Но у фичи есть особенности:
Readonly-классы недоступны для классов с необъявленными типами.
Также readonly-классы недоступны для классов со статическими свойствами.
Если мы захотим наследоваться от старого readonly-класса, новый тоже должен быть Readonly.
Теперь вместо того, чтобы указывать тип mixed для аргументов в методах, можно просто перечислять необходимые типы [6] через амперсанд.
Как выглядел код в предыдущих версиях PHP:
class Foo {
public function bar(mixed $entity) {
if ((($entity instanceof A) && ($entity instanceof B)) || ($entity === null)) {
return $entity;
}
throw new Exception('Invalid entity');
}
}
Как выглядит код в PHP 8.2:
class Foo {
public function bar((A&B)|null $entity) {
return $entity;
}
}
Пожелание от меня: будьте осторожны с этой фичей. Она позволяет много методов объединять в один. Если бы я программировал приложения, то так не делал бы. А вот во фреймворках она будет очень кстати, потому что иногда, ради красивой API, мы сознательно жертвуем такой вот правильностью — используем подход с mixed-типами в сигнатуре.
Это изменение единогласно приняла вся команда разработчиков PHP, так как в ядре PHP есть методы, классы и функции, которые возвращают false или true.
Если у вас метод никогда не возвращает false, то теперь можно указать [7], что он возвращает true или значение. Или наоборот, null и значение, или false и значение. Фича удобная и делает язык немного строже.
Как выглядел код в предыдущих версиях PHP:
class Falsy
{
public function almostFalse(): bool { /* ... */ *}
public function almostTrue(): bool { /* ... */ *}
public function almostNull(): string|null { /* ... */ *}
}
Как выглядит код в PHP 8.2:
class Falsy
{
public function alwaysFalse(): false { /* ... */ *}
public function alwaysTrue(): true { /* ... */ *}
public function alwaysNull(): null { /* ... */ *}
}
Random [8] — это целый пак разных интерфейсов. Особенности фичи:
Разработчики сделали объектно-ориентированный API.
Каждый инстанс независимый — то есть для разных целей можно инстанцировать n-штук псевдослучайных генераторов, которые никогда не пересекутся. Стало более безопасно.
Mersenne twister заменен на интерфейс Engine. Раньше mt_rand() надо было инициализировать. Он был нужен не для всяких крипто-фич, а для того чтобы, например, сортировать массивы в случайном порядке. mt_rand() работал достаточно быстро, поэтому использовать его для утилитарных задач было неплохо. Теперь его заменили на интерфейс Engine, который предоставляет готовые реализации.
Как выглядит код в PHP 8.2:
use RandomEngineXoshiro256StarStar;
use RandomRandomizer;
$blueprintRng = new Xoshiro256StarStar(
hash('sha256', "Example seed that is converted to a 256 Bit string via SHA-256", true)
);
$fibers = [];
for ($i = 0; $i < 8; $i++) {
$fiberRng = clone $blueprintRng;
// Xoshiro256**'s 'jump()' method moves the blueprint ahead 2**128 steps, as if calling
// 'generate()' 2**128 times, giving the Fiber 2**128 unique values without needing to reseed.
$blueprintRng->jump();
Теперь можно объявлять константы внутри трейтов [9]. Особенность фичи — нельзя получить доступ к константе через имя трейта, но можно через класс, который использует этот трейт.
Очень логичное изменение, на мой взгляд. Трейт сам по себе — это копипаст. Копипаст — штука опасная, но иногда полезная (у нас есть принцип «don't repeat yourself»). И трейт — это один самых неинвазивных способов что-то повторить, который легко потом отрефакторить.
Как выглядит код в PHP 8.2:
trait Foo
{
public const CONSTANT = 1;
}
class Bar
{
use Foo;
}
var_dump(Bar::CONSTANT); // 1
var_dump(Foo::CONSTANT); // Error
В классах PHP можно было динамически присваивать значения свойствам, которые мы не объявили ранее, и эти свойства появлялись после классов.
Теперь так сделать нельзя [10] — будет появляться Deprecation notice. Но если сильно нужно, динамическими свойствами можно пользоваться, если пометить класс аннотацией #[AllowDynamicProperties]. В экземплярах stdClass динамические свойства по-прежнему можно использовать.
Как выглядел код в предыдущих версиях PHP:
class User
{
public $name;
}
$user = new User();
$user->last_name = 'Doe';
$user = new stdClass();
$user->last_name = 'Doe';
Как выглядит код в PHP 8.2:
class User
{
public $name;
}
$user = new User();
$user->last_name = 'Doe'; // Deprecated notice
$user = new stdClass();
$user->last_name = 'Doe'; // Still allowed
Это маленькая, но очень классная фича, которая мельком упоминается в официальном анонсе.
Параметры в методах теперь можно обозначить [11] как #[SensitiveParameter]. Ниже в коде так отмечен параметр $secret, и в логах вместо значения параметра secret написано (Object(SensitiveParameterValue).
function sensitiveParametersWithAttribute(
#[SensitiveParameter]
string $secret,
string $normal
) {
throw new Exception('Error!');
}
Exception: Error! in example.php:15
Stack trace:
#0 example.php(25): sensitiveParametersWithAttribute(Object(SensitiveParameterValue), 'normal')
#1 {main}
Считаю это изменение очень крутым, так как теперь у нас не будут утекать всякие ключи от API, пароли от базы. Команда разработчиков PHP практически единогласно проголосовала за эту фичу.
Раньше, чтобы использовать enum, надо было дублировать их значение. Это было очень неприятно: enum есть, а в объявлениях констант нельзя было из них что-то использовать. Теперь можно: новая фича уравнивает весь синтаксис. Классно, что язык эволюционирует в сторону удобства и большей консистентности.
const C = [self::B->value => self::B];
Теперь можно передавать [12] в методы iterator_() тип Traversables. Это просто замечательно, потому что раньше приходилось проверять, является ли аргумент объектом типа Traversable, и если да, то надо было его конвертить. В PHP 8.2 можно больше не проводить эти проверки, что уменьшает количество кода и делает его более приятным и читаемым.
Можно узнать, анонимный ли метод [13] — ReflectionFunction::isAnonymous()
Можно узнать, есть ли у метода прототип [14] — ReflectionMethod::hasPrototype()
Функции сбрасывают статистику [15] по пиковому использованию памяти. Это очень полезно для EventLoop на PHP, Roadrunner и Swoole — мы сможем скинуть потребляемую память после запроса и измерить ту, которая ушла конкретно на один запрос.
Интерполяция в строках вида ${}
Не рекомендуется использовать функции utf8_encode и utf8_decode
Функции strtolower и strtoupper теперь не учитывают локаль — это круто, потому что версии PHP, установленные в двух системах Linux, могут работать по-разному из-за выбранной дефолтной локали.
Убрали много форматов callable:
“self::method”
“parent::method”
“static::method”
[“self”, “method”]
[“parent”, “method”]
[“static”, “method”]
[“Foo”, “Bar::Method”]
[new Foo, “Bar::Method”]
Мое мнение — на PHP 8.2 определенно стоит переходить хотя бы из-за крутых улучшений синтаксиса. Он все еще делает код более читаемым и понятным. Также разработчики пофиксили разные мелкие баги, которые мы не упомянули, но их было много.

Некоторые разработчики считают, что в новую версию PHP добавили очень мало изменений. На самом деле, в РHP 8.2 было много саппортных вещей: код вычищали, из него что-то убирали. Каждое изменение, которое вводили разработчики, непросто описать в фичах. Да и вряд ли всем будет интересно, какие куски кода рефакторили. Так что по объему работы релиз 8.2 не отличается от предыдущих релизов. Просто в нем чуть меньше фич.
Большие усилия к разработке версии 8.2 приложили ребята из PHP Foundation — проекта, который финансирует разработчиков, готовых контрибьютить в PHP.

PHP Foundation создали много известных компаний, среди которых JetBrains, Automattic, Laravel. Проект запустили 22 ноября 2021 года, и за год коллектив из десяти администраторов-добровольцев и шести разработчиков внесли почти половину коммитов в ядро языка PHP и расширения.
В новую версию языка PHP Foundation имплементировал интерполяцию в строках вида ${}, readonly-классы, самостоятельные типы null, false и true, тип true, типы в виде дизъюнктивной нормальной формы и получение свойств перечислений в константных выражениях.
Документация по PHP 8.2 еще в разработке, и разработчик PHP Foundation Джордж П. Баньярд сейчас отслеживает прогресс в изменениях. Вместе с командой он обсуждает эти нововведения:
Помочь составить документацию [22] может каждый из нас — это, как говорится, good first issue (несложные задачи, выполнить которые под силу новичкам).
Также PHP Foundation планирует выдвинуть на обсуждение новые изменения в будущем релизе PHP 8.3 [23].
Автор:
S__vet
Источник [24]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/381295
Ссылки в тексте:
[1] @SamDark: https://www.pvsm.ru/users/samdark
[2] @vudaltsov: https://www.pvsm.ru/users/vudaltsov
[3] @funkylen: https://github.com/funkylen
[4] ежегодный опрос: https://forms.gle/4DU4rzQu4cHEhkCj7
[5] отметить весь класс: https://wiki.php.net/rfc/readonly_classes
[6] перечислять необходимые типы: https://wiki.php.net/rfc/dnf_types
[7] можно указать: https://wiki.php.net/rfc/null-false-standalone-types
[8] Random: https://wiki.php.net/rfc/rng_extension
[9] объявлять константы внутри трейтов: https://wiki.php.net/rfc/constants_in_traits
[10] так сделать нельзя: https://wiki.php.net/rfc/deprecate_dynamic_properties
[11] можно обозначить: https://www.php.net/manual/ru/class.sensitive-parameter.php
[12] можно передавать: https://www.php.net/manual/ru/migration82.other-changes.php#migration82.other-changes.core
[13] анонимный ли метод: https://www.php.net/manual/ru/reflectionfunction.isanonymous.php
[14] есть ли у метода прототип: https://www.php.net/manual/ru/reflectionmethod.hasprototype.php
[15] сбрасывают статистику: https://www.php.net/manual/ru/function.memory-reset-peak-usage.php
[16] Автоматическая имплементация для enum Stringable: https://wiki.php.net/rfc/auto-implement_stringable_for_string_backed_enums
[17] Ассиметричная видимость: https://wiki.php.net/rfc/asymmetric-visibility
[18] Получение констант из класса: https://wiki.php.net/rfc/dynamic_class_constant_fetch
[19] Более понятные ошибки Date/Time: https://wiki.php.net/rfc/datetime-exceptions
[20] Доработки по Readonly: https://wiki.php.net/rfc/readonly_amendments
[21] Работа с инициализаторами произвольных статических переменных: https://wiki.php.net/rfc/arbitrary_static_variable_initializers
[22] составить документацию: https://github.com/php/doc-en/issues/1803
[23] будущем релизе PHP 8.3: https://wiki.php.net/rfc/deprecations_php_8_3
[24] Источник: https://habr.com/ru/post/705194/?utm_source=habrahabr&utm_medium=rss&utm_campaign=705194
Нажмите здесь для печати.