Всё, что появилось в PHP 8.5
Оператор конвейера |>
В PHP 8.5 введён оператор pipe/конвейера (|>), позволяющий писать код в беcточечном стиле, ограничивающем использование необязательных промежуточных переменных.
Итак, следующий код…
$value = "hello world";
$result1 = function3($value);
$result2 = function2($result1);
$result = function1($result2);…можно переписать с помощью оператора конвейера так:
$value = "hello world";
$result = $value
|> function3(...)
|> function2(...)
|> function1(...);Оператор |>, или "pipe", принимает вызываемый объект с одним параметром справа и передаёт ему значение с левой стороны, вычисляя результат вызываемого объекта. Конвейер (|>) вычисляется слева направо, передавая значение (или результат выражения) слева в качестве первого и единственного параметра вызываемому объекту справа.
Вот более реальный пример:
$fullName = 'Fred Flintstone';
$result = $fullName
|> fn($x) => explode(' ', $x) // Создаёт массив отдельных слов
|> fn($x) => implode('_', $x) // Соединяет эти слова с помощью символа _
|> strtolower(...) // Преобразует всё в нижний регистр
;
// $result === 'fred_flintstone'Новые методы массива
В PHP 8.5 добавлены две новые функции массива, array_first() и array_last(), упрощающие получение первого и последнего элементов массива без изменения внутреннего указателя и использования ключей.
$array = [1, 2, 3, 4, 5];
$first = array_first($array); // 1
$last = array_last($array); // 5
$array = ['a' => 1, 'b' => 2, 'c' => 3];
$first = array_first($array); // 1
$last = array_last($array); // 3Для пустых массивов обе функции возвращают null вместо выброса ошибки.
$first = array_first([]); // null
$last = array_last([]); // nullАтрибут #[\NoDiscard]
В PHP 8.5 добавлен новый атрибут #[\NoDiscard], позволяющий разработчикам указывать, что возвращаемое значение функции или метода не должно игнорироваться. Если разработчик вызывает функцию, помеченную #[\NoDiscard], и не использует возвращаемое значение, PHP выдаст предупреждение.
#[\NoDiscard("as the operation result is important")]
function performOperation(): int {
// Выполнение какой-либо операции
return 1; // 1 — в случае успеха, 0 — в случае неудачи
}
// Вызов функции без использования возвращаемого значения
// Warning: The return value of function performOperation() is expected to be consumed, as the operation result is important in test.php on line 10
performOperation();
// Вызов функции и использование возвращаемого значения
// Это действие не вызовет предупреждение.
$status = performOperation();Это отличный способ убедиться, что разработчики случайно не проигнорируют важные возвращаемые значения, особенно в тех случаях, когда возвращаемое значение имеет решающее значение для успеха или неудачи операции.
Новый URL/URI API
В PHP 8.5 введён стандартизированный API, позволяющий анализировать, нормализовать, изменять и сравнивать URI/URL в соответствии с соответствующими спецификациями.
Для анализа и работы с адресами вводятся два иммутабельных класса.
Uri\Rfc3986\Uri: соответствует RFC 3986 (generic URI, строгая валидация, опциональная нормализация, процентное декодирование, где это безопасно)
Uri\WhatWg\Url: соответствует WHATWG URL (поведение браузера, хосты IDNA/Unicode, преобразования во время анализа, soft/hard ошибки)
Далее приведено как их использовать для анализа и безопасной проверки URL.
use Uri\Rfc3986\Uri;
use Uri\WhatWg\Url;
$rfc = Uri::parse("https://example.com/path?x=1"); // Uri или null
$whatwg = Url::parse("https://example.com/path?x=1"); // Url или null
$bad = Uri::parse("invalid uri"); // null (ошибка strict)
$errors = [];
$bad2 = Url::parse(" invalid url", null, $errors); // null с информацией о soft/hard ошибкахПродвижение final свойства
class Example {
public function __construct(
final string $id
) {}
}- Свойство
$idтеперь является как продвинутым (созданным и инициализированным через конструктор), так иfinal(не может быть переопределено). - Если используете
final, не нужно указывать видимость (например,publicилиprivate); по умолчанию онаpublic, но при желании можно комбинироватьfinalс видимостью.
Это делает синтаксис продвижения свойств конструктора более последовательным, и уменьшает количество шаблонного кода, который необходимо писать.
Атрибуты констант
Как вы, возможно, знаете, атрибуты — способ добавления метаданных к элементам кода (таким как классы, методы, свойства и т. д.) с помощью специального синтаксиса. Например:
#[MyAttribute]
class MyClass {}Теперь, с PHP 8.5, помимо таких вещей, как классы, методы и константы классов, можно также добавлять атрибуты к глобальным (неклассовым) константам.
Теперь можно добавлять атрибуты к неклассовым константам периода компиляции, например:
#[MyAttribute]
const MY_CONST = 42;Следует иметь в виду, что это не работает для констант, определённых с помощью define(), а только для объявленных с помощью const.
Теперь можно использовать ReflectionConstant::getAttributes() для чтения атрибутов констант в runtime. Кроме того, атрибут #[\Deprecated] обновлён, чтобы позволить ориентироваться на константы; при применении константа помечается как CONST_DEPRECATED.
#[Deprecated(reason: 'Use NEW_API_URL instead. This will be removed in v2.0.')]
const OLD_API_URL = 'https://old-api.example.com';
const NEW_API_URL = 'https://api.example.com';
// Пример использования
function fetchData() {
// IDE и статические анализаторы теперь могут предупреждать об использовании OLD_API_URL
$data = file_get_contents(OLD_API_URL);
return $data;
}Улучшенный класс Directory
В PHP 8.5 класс Directory изменён так, что теперь он ведёт себя как строгий, немодифицируемый ресурсный объект. По сути, класс Directory в PHP используется для представления дескрипторов каталогов, обычно создаваемых функцией dir(). Исторически он вёл себя как обычный класс, но это могло приводить к ошибкам и неправильному использованию (например, созданию недопустимых объектов Directory с помощью new Directory()).
Чтобы исправить это, в PHP 8.5 класс Directory ведёт себя как настоящий "ресурсный объект" (иногда называемый "непрозрачным объектом").
Это означает:
- Конечный класс: Нельзя расширять (наследовать) класс
Directory. - Отсутствие прямого создания экземпляров: Нельзя создать объект
Directoryс помощьюnew Directory(). Только функцияdir()может создавать валидные экземпляры. - Отсутствие клонирования: Нельзя клонировать объект
Directory. - Отсутствие сериализации: Нельзя сериализовать или десериализовать объекты
Directory. - Отсутствие динамических свойств: Нельзя добавлять новые свойства к объектам
Directoryво время выполнения.
Теперь, при попытке создать объект Directory с помощью new Directory(), будет выброшена ошибка:
$dir = new Directory(); // Выбрасывает ошибку
$dir = dir('/tmp'); // Корректный способ создания объекта DirectoryТрассировка фатальных ошибок
PHP 8.5 появилась автоматическая трассировка стека к сообщениям о фатальных ошибках PHP, что значительно упростит отладку.
До PHP 8.5, когда происходит фатальная ошибка (например, истечение времени выполнения или памяти), сообщение об ошибке не содержит трассировку (список вызовов функций, которые привели к ошибке). Без трассировки трудно понять, что вызвало ошибку, особенно в больших или сложных кодовых базах.
Когда эта опция включена (а она может быть включена по умолчанию), PHP будет выводить трассировку стека для фатальных ошибок. Трассировка стека показывает последовательность вызовов функций, приведших к ошибке, аналогично тому, что вы видите при исключениях.
Так выглядела трассировка ранее:
Fatal error: Maximum execution time of 1 second exceeded in example.php on line 7После включения новой опции INI она будет выглядеть следующим образом:
Fatal error: Maximum execution time of 1 second exceeded in example.php on line 6
Stack trace:
#0 example.php(6): usleep(100000)
#1 example.php(7): recurse()
#2 example.php(7): recurse()
...
#11 {main}Ключевые моменты о новой трассировке ошибок:
- Чтобы избежать проблем с производительностью и памятью, трассировка выполняется только для фатальных ошибок (а не для предупреждений или уведомлений).
- Трассировка учитывает настройки конфиденциальности (например, атрибуты
SensitiveParameter). - Трассировка также доступна программно через
error_get_last()в функциях завершения работы.
Улучшения постоянных дескрипторов cURL
PHP 8.5 улучшает способ управления постоянными дескрипторами cURL, делая их более безопасными и простыми в использовании.
По сути, дескрипторы cURL позволяют нескольким запросам cURL совместно использовать данные (например, кэш DNS) для повышения эффективности. Недавно в PHP была добавлена поддержка постоянных дескрипторов cURL, которые можно повторно использовать в нескольких PHP запросах. Первоначальная реализация имела некоторые риски и проблемы с удобством использования, особенно в отношении совместного использования cookie-файлов и управления постоянными идентификаторами.
PHP 8.5 вводит новую функцию curl_share_init_persistent(), создающую постоянный дескриптор cURL. Эта функция более безопасна и последовательна, чем предыдущая curl_share_init(). Больше не нужно предоставлять настраиваемый постоянный идентификатор; PHP управляет этим автоматически на основе переданных вами параметров. Если повторно вызвать функцию с теми же параметрами, вы получите тот же дескриптор (он будет повторно использован).
$options = [CURL_LOCK_DATA_DNS];
$shareHandle = curl_share_init_persistent($options);
//Использование $shareHandle с CURLOPT_SHARE в запросах cURL
curl_setopt($ch, CURLOPT_SHARE, $shareHandle);Это улучшение важно, поскольку предотвращает случайную передачу конфиденциальных cookie-файлов. Кроме того, разработчикам не нужно управлять постоянными идентификаторами или беспокоиться о несоответствии дескрипторов.
Callable объекты первого класса в константных выражениях
PHP 8.5 позволит использовать callable объекты первого класса (FCC) в константных выражениях PHP.
Как вы, возможно, знаете, callable объекты первого класса — это лаконичный способ ссылки на функции или статические методы в качестве вызываемых объектов с помощью синтаксиса … . Например:
// $callable теперь callable strlen()
$callable = strlen(...);
// callable MyClass::myMethod()
$callable = MyClass::myMethod(...);Раньше нельзя было использовать FCC внутри константных выражений (таких как значения свойств по умолчанию, аргументы атрибутов или определения констант). В PHP 8.5 это изменилось, и теперь можно использовать FCC в константных выражениях.
const MY_CALLABLE = strlen(...);
#[Attr(self::myMethod(...))]
class C {}Это делает использование FCC более последовательным в PHP и упрощает определение повторно используемых callable объектов в качестве констант, их использование в атрибутах или в качестве значений по умолчанию, что делает код более выразительным и DRY.
Использование замыканий в константных выражениях
PHP 8.5 позволит использовать статические замыкания (анонимные функции) в константных выражениях PHP. Чтобы понять, что изменилось, давайте сначала разберёмся, что такое константные выражения.
Константное выражение в PHP — это значение, которое должно быть полностью определено во время компиляции. Примеры:
- Значения по умолчанию для параметров функций.
- Аргументы атрибутов.
- Константы классов.
- Значения по умолчанию свойств.
До PHP 8.5 в константах нельзя было использовать замыкания (анонимные функции). В PHP 8.5 это изменилось. Теперь можно делать что-то вроде этого.
function my_array_filter(
array $array,
Closure $callback = static function ($item) { return !empty($item); }
) {
// ...
}Или используйте замыкания в качестве аргументов атрибутов, значений свойств по умолчанию или констант классов.
Существует несколько ограничений:
- Должно быть статическим: замыкание не может использовать
$thisили захватывать переменные из окружающей области видимости (нельзя использоватьuse($foo)и стрелочные функции). - Запрет на захват переменных: допускаются только чистые статические замыкания, поскольку константные выражения не могут зависеть от runtime-значений.
- Проверка во время компиляции: PHP выдаст ошибку, если попытаться использовать нестатическое замыкание или замыкание, захватывающее переменные.
Возможность использовать замыкания в константных выражениях позволяет писать более чистый код, поскольку можно предоставлять стандартные обратные вызовы или валидаторы непосредственно в сигнатурах функций, атрибутах или константах.
Кроме того, библиотеки могут использовать замыкания в атрибутах для таких целей, как валидация, форматирование или генерация наборов тестов, как показано ниже.
final class Locale
{
#[Validator\Custom(static function (string $languageCode): bool {
return preg_match('/^[a-z][a-z]$/', $languageCode);
})]
public string $languageCode;
}final class CalculatorTest
{
#[Test\CaseGenerator(static function (): iterable {
for ($i = -10; $i <= 10; $i++) {
yield [$i, $i, 0];
yield [$i, 0, $i];
yield [0, $i, ($i * -1)];
}
})]
public function testSubtraction(int $minuend, int $subtrahend, int $result)
{
\assert(Calculator::subtract($minuend, $subtrahend) === $result);
}
}final class LogEntry
{
public string $message;
#[Serialize\Custom(static function (string $severity): string {
return \strtoupper($severity);
})]
public string $severity;
}В целом, это хорошее улучшение, делающее код более выразительным и лаконичным.
Функции обработки ошибок и исключений
В PHP 8.5 добавлены функции get_error_handler() и get_exception_handler(), позволяющие напрямую получать текущие обработчики ошибок и исключений.
В PHP можно настроить собственные обработчики ошибок и исключений с помощью функций set_error_handler() и set_exception_handler(). Однако не было прямого способа проверить, какой обработчик используется в данный момент.
Разработчикам приходилось использовать обходной путь: устанавливать новый обработчик, сохранять старый, а затем восстанавливать его, что было неудобным и чреватым ошибками процессом.
В PHP 8.5 добавлены две новые функции:
get_error_handler(): ?callableget_exception_handler(): ?callable
Эти функции возвращают текущий зарегистрированный обработчик ошибок или исключений, либо null, если ни один из них не установлен.
set_error_handler(null);
get_error_handler(); // null
$handler = [$this, 'error_handler'];
set_error_handler($handler);
get_error_handler() === $handler; // true
$new_handler = $this->error_handler(...);
$old_handler = set_error_handler($new_handler);
get_error_handler() === $new_handler; // true
restore_error_handler();
get_error_handler() === $old_handler; // trueКак можно догадаться, это делает процесс настройки обработчиков надёжным, поскольку вы получаете именно тот обработчик, который настроили, что упрощает отладку и управление обработчиками.
Кроме того, фреймворки и библиотеки теперь могут безопасно проверять или восстанавливать обработчики без побочных эффектов.
Асимметричная видимость для статических свойств
PHP 8.5 позволяет статическим свойствам в PHP иметь асимметричную видимость, то есть их доступ для чтения и записи может иметь разные уровни видимости.
В качестве примера можно привести асимметричную видимость, введённую в PHP 8.4, позволяющую устанавливать разные уровни доступа для чтения и записи свойства. Например, свойство может быть public для чтения, но private или protected для записи.
Ранее асимметричная видимость была доступна только для свойств объектов (экземпляров). С PHP 8.5 её можно использовать и для статических свойств.
class Example
{
public private(set) static string $classTitle = 'Example class';
// Все могут прочитать Example::$classTitle, но изменить его может только сам класс.
protected(set) static int $counter = 0;
// Любой может прочитать Example::$counter, но только класс или дочерние классы могут его изменить.
public static function changeName(string $name): void
{
self::$classTitle = $name; // Разрешено (внутри класса)
}
}
echo Example::$classTitle; // Разрешено (public чтение)
Example::$classTitle = 'Nope'; // Запрещено (private запись)Это делает функцию асимметричной видимости более последовательной во всем языке.
Новая функция Левенштейна для группы графем
В PHP 8.5 добавлена новая функция grapheme_levenshtein(), позволяющая точно сравнивать строки по группам графем (символам, воспринимаемым пользователем), а не по байтам или кодовым точкам.
По сути, расстояние Левенштейна измеряет, сколько односимвольных изменений (вставок, удалений, замен) необходимо для преобразования одной строки в другую. Существующие в PHP функции levenshtein() и mb_levenshtein() работают с байтами или кодовыми точками Unicode, что может давать неверные результаты для сложных символов Unicode (таких как эмодзи или буквы с диакритическими знаками).
Группа графем — это то, что пользователь видит как один символ, даже если он состоит из нескольких кодовых точек Unicode (например, «é» может быть одной кодовой точкой или «e» плюс комбинируемый акцент).
Чтобы это учесть, в PHP 8.5 введена функция grapheme_levenshtein(), вычисляющая расстояние Левенштейна на основе групп графем. Это означает, что она рассматривает визуально идентичные символы как одинаковые, даже если их базовое кодирование различается.
var_dump(
grapheme_levenshtein(
"\u{0065}\u{0301}",
"\u{00e9}"
)
); // Результат: 0Здесь обе строки отображаются пользователю как «é», но кодируются по-разному. Новая функция правильно распознает их как идентичные.
Новая опция INI diff
В PHP 8.5 добавлена опция INI diff, отображающая все настройки INI, отличающиеся от встроенных настроек PHP по умолчанию.
php --ini=diffЭта команда выводит список всех директив конфигурации INI, изменённых по сравнению с их встроенными значениями по умолчанию. Это быстрый способ увидеть, какие настройки были настроены в вашей среде, что особенно удобно для отладки, устранения неполадок или обмена информацией о различиях в конфигурации.
Non-default INI settings:
memory_limit: "128M" -> "512M"
display_errors: "1" -> ""
date.timezone: "UTC" -> "Europe/Amsterdam"Здесь левое значение является значением по умолчанию, а правое — текущей настройкой. Кроме того, отображаются только настройки, отличающиеся от значений по умолчанию.
Это позволяет быстро обнаружить изменения в конфигурации, влияющие на поведение приложения, и легко сравнивать различные среды (dev, stage, prod).
Также это позволяет увидеть, что изменилось в контейнерных или автоматизированных настройках.
Клонирование объектов со свойствами
PHP 8.5 представляет новый способ клонирования PHP объектов и изменения их свойств в один шаг.
В PHP существуют readonly свойства и клонирование объектов, но они не очень хорошо работают вместе. Обычно используется шаблон с иммутабельными объектами и методами, такими как withProperty(), возвращающими новый объект с одним изменённым свойством. С readonly свойствами сложно создать новый объект с одним изменённым свойством, потому что readonly свойства нельзя изменять после создания.
Для смягчения этой проблемы в PHP 8.5 clone работает как функция, принимающая второй аргумент: массив свойств, подлежащих изменению в новом объекте.
clone($object, $withProperties)Например:
$newObj = clone($oldObj, ['property' => $newValue]);Это создаст копию $oldObj, но со свойством, установленным в $newValue в клоне, даже если оно readonly.
Новую функцию clone() можно использовать следующим образом:
clone $obj;(старый способ, по-прежнему работает)clone($obj);(новый стиль функции)clone($obj, ['foo' => 42]);(клонирование и изменение свойств)
Вы также можете использовать clone как вызываемый объект, например, в array_map('clone', $arrayOfObjects);. Правила видимости свойств соблюдаются: можно изменять только те свойства, к которым есть доступ.
Следует иметь в виду, что магический метод __clone() вызывается до того, как будут установлены новые свойства.
Ещё один пример использования нового метода клонирования объекта и изменения его свойств.
class Foo {
public function __construct(
private readonly int $c = 1,
) {}
public function clone_with($newC) {
return clone($this, ["c" => $newC]);
}
}
$x = new Foo();
$y = $x->clone_with(5);
// $y->c 5Так же можно использовать его как вызываемый объект.
$objects = [new stdClass, new stdClass];
$clones = array_map('clone', $objects);
foreach ($clones as $clone) {
// Работаем с каждым клоном
}В целом, новый метод clone значительно упрощает работу с иммутабельными объектами и readonly свойствами. Также сокращается количество шаблонного кода для создания модифицированных копий объектов.
Всегда загруженное расширение OPCache
OPcache — встроенное расширение PHP, ускоряющее работу PHP за счёт кэширования скомпилированного байт-кода скрипта в памяти. Оно является частью PHP с версии 5.5, но до сих пор было опциональным, то есть PHP можно было запускать и без него.
Запуск PHP без OPcache считается ошибкой для продакшена, но всё ещё возможен (особенно в Docker или пользовательских сборках). Поддержка PHP с OPcache и без него означает, что разработчики должны поддерживать два разных пути кода, что может привести к возникновению багов и затрудняет поддержку PHP.
PHP 8.5 делает OPcache обязательной, всегда загружаемой частью PHP. По сути, это означает, что его нельзя отключить во время сборки (--disable-opcache удалено).
Возможности OPcache (такие как кэширование и оптимизация) по-прежнему можно включать или отключать с помощью INI настроек (opcache.enable, opcache.enable_cli), но само расширение всегда присутствует.
Как разработчику, вам не нужно делать ничего особенного. Начиная с PHP 8.5, нельзя запускать PHP без загруженного OPcache, но по-прежнему можно контролировать поведение OPcache с помощью настроек конфигурации. Однако никаких изменений в использовании OPcache в вашем коде не произойдёт.
Новый флаг расширения filter для генерации исключений при ошибке валидации
PHP 8.5 улучшает PHP расширение filter, используемое для проверки и очистки входящих данных (например, для валидации адреса электронной почты). В настоящее время, если валидация не проходит, функции фильтра возвращают false или null, и разработчики должны вручную проверять эти значения и при необходимости генерировать исключения.
Введён новый флаг: FILTER_THROW_ON_FAILURE. При его использовании функция фильтра автоматически генерирует исключение в случае неудачной валидации, вместо возврата false или null.
Так обычно проверяется адрес электронной почты без использования нового флага:
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
return false;
}Как видите, вам необходимо вручную проверять возвращаемое значение и обрабатывать ошибку.
С помощью нового флага FILTER_THROW_ON_FAILURE задача упрощается:
try {
filter_var($email, FILTER_VALIDATE_EMAIL, FILTER_THROW_ON_FAILURE);
return true;
} catch (\Filter\FilterFailedException $e) {
return false;
}В данном случае, если адрес электронной почты недопустим, генерируется исключение FilterFailedException, которое можно перехватить и обработать. Это делает код более чистым и снижает вероятность забыть проверить возвращаемое значение.
Следует помнить, что нельзя использовать FILTER_THROW_ON_FAILURE вместе с FILTER_NULL_ON_FAILURE, так как это приведёт к возникновению ошибки ValueError.
Положение об отметке трейтов как устаревших
PHP 8.5 позволяет пометить трейты как устаревшие с помощью атрибута #[\Deprecated], предупреждая разработчиков при их использовании.
Если класс использует этот трейт, PHP выдаст предупреждение об устаревании. Это поможет разработчикам узнать, что трейт больше не следует использовать, и даст им время обновить код до того, как трейт будет удалён.
Пример, как пометить трейт как устаревший:
#[\Deprecated]
trait DemoTrait {}
class DemoClass {
use DemoTrait;
}
// Output:
// Deprecated: Trait DemoTrait used by DemoClass
// is deprecated in [file] on line [number]Как видите, когда DemoClass использует устаревший DemoTrait, PHP выдаёт предупреждение, указывающее, что этот трейт устарел.
Важно отметить, что предупреждение отображается только в том случае, если класс напрямую использует устаревший трейт. Если родительский класс использует этот трейт, дочерние классы не получают дополнительных предупреждений, если они не используют этот трейт напрямую.
Добавление локали для нечувствительных к регистру функций графем
PHP 8.5 улучшает несколько функций строк графем, добавляя параметр $locale. Функции графем работают с воспринимаемыми пользователем символами ( графемами), важными для правильной обработки Unicode текста.
Ранее эти функции не учитывали локаль, то есть обрабатывали весь текст одинаково, независимо от языка или региона. Однако в некоторых языках существуют специальные правила сопоставления, не учитывающие регистр. Например, турецкая буква «İ» (заглавная точечная «I») обрабатывается иначе, чем в английском языке.
Пример работы нового параметра $locale с grapheme_stripos():
var_dump(grapheme_stripos("i", "\u{0130}", 0, "tr_TR")); // Возвращает 0 (совпадает в турецком языке)
var_dump(grapheme_stripos("i", "\u{0130}", 0, "en_US")); // Возвращает false (не совпадает в английском языке)Следующие функции стали принимать параметр $locale:
grapheme_strposgrapheme_striposgrapheme_strrposgrapheme_strriposgrapheme_substrgrapheme_strstrgrapheme_stristrgrapheme_levenshtein
Кроме того, можно указать «силу» (степень строгости сравнения символов) с помощью строки locale, что особенно полезно для CJK (Chinese, Japanese, Korean) символов.
$nabe = '邊';
$nabe_E0101 = "邊\u{E0101}";
var_dump(
grapheme_levenshtein(
$nabe,
$nabe_E0101
)
); // Результат: 0
var_dump(
grapheme_levenshtein(
$nabe,
$nabe_E0101,
locale: "ja_JP-u-ks-identic"
)
); //Результат: 1Плавное устаревание магических методов __sleep() и __wakeup()
В PHP 8.5 реализовано плавное выведение из употребления магических методов __sleep() и __wakeup() — они будут продолжать работать, но в документации помечены как устаревшие, и вместо них будет предложено использовать __serialize()/__unserialize().
Пример:
class User {
public function __construct(
public readonly string $id,
public readonly string $email,
public readonly DateTime $createdAt
) {}
public function __sleep(): array {
return ['id', 'email', 'createdAt'];
}
public function __wakeup(): void {
$this->validate();
}
private function validate(): void {
if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
}
}После миграции на __serialize()/__unserialize():
public function __serialize(): array {
return [
'id' => $this->id,
'email' => $this->email,
'createdAt' => $this->createdAt,
];
}
public function __unserialize(array $data): void {
$this->validateData($data);
$this->id = $data['id'];
$this->email = $data['email'];
$this->createdAt = $data['createdAt'];
}Авторы этого RFC утверждают, что жёсткое прекращение поддержки не учитывает сложность миграции, особенно в случае больших классов, изменения имён приватных свойств, совместимости сохранённых данных и наследования. Они демонстрируют, что миграция часто добавляет шаблонный код, создаёт риск поломки и даёт мало преимуществ в простых случаях.
Планируется обновить документацию в пользу нового API, избежать принудительной переделки кода сейчас и рассмотреть возможность реального прекращения поддержки позже, когда пути миграции станут более ясными.
Итак, суть в том, что, поскольку это плавное прекращение поддержки, __sleep() и __wakeup() продолжают работать. Изменение в документации: теперь PHP рекомендует в дальнейшем использовать __serialize()/__unserialize(). Можно оставить существующий код без изменений и мигрировать в удобный для вас момент.