AVSoft

Связаться через Telegram

Что нового в PHP 8.5?

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

Что нового в PHP 8.5?

Рассмотрим его основные изменения.


Оператор Pipe

Оператор Pipe (|>), также называемый конвейерным оператором, позволяет связывать вызовы функций в цепочку без использования промежуточных переменных. То есть теперь вместо такой записи:

$input = ' Pipe operator in PHP 8.5 '; $slug = strtolower( str_replace('.', '', str_replace(' ', '-', trim($input) ) ) );

или такой:

$input = ' Pipe operator in PHP 8.5 '; $temp = trim($input); $temp = str_replace(' ', '-', $temp); $temp = str_replace('.', '', $temp); $slug = strtolower($temp);

можно делать так:

$input = ' Pipe operator in PHP 8.5 '; $slug = $input |> trim(...) |> (fn($str) => str_replace(' ', '-', $str)) |> (fn($str) => str_replace('.', '', $str)) |> strtolower(...);

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


Функции array_first() и array_last()

Функции array_first() и array_last() возвращают первое или последнее значение массива, соответственно. В случае, если массив пустой, возвращается null. Теперь вместо использования тернарного оператора:

$firstEl = $array === [] ? null : $array[array_key_first($array)]; $lastEl = $array === [] ? null : $array[array_key_last($array)];

можно использовать новые функции:

$firstEl = array_first($array); $lastEl = array_last($array);

Благодаря этим функциям работать с массивами станет гораздо проще.


Функция grapheme_levenshtein()

Существующие в PHP функции levenshtein() и mb_levenshtein() работают с байтами или кодовыми точками Unicode, что может давать неверные результаты для сложных символов Unicode, таких как эмодзи или буквы с диакритическими знаками. Новая функция grapheme_levenshtein() вычисляет расстояние Левенштейна на основе графем — единиц текста, которые пользователь видит как один символ, даже если они состоят из нескольких кодовых точек Unicode, например:

var_dump( grapheme_levenshtein( "\u{00e9}", // é "\u{0065}\u{0301}" // e + комбинирующий акут, визуально тоже é ) ); // Результат: 0

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


Функции get_error_handler() и get_exception_handler()

В PHP можно настроить собственные обработчики ошибок и исключений с помощью функций set_error_handler() и set_exception_handler(). Однако ранее не было простого способа проверить, какой обработчик используется в данный момент. Функции get_error_handler() и get_exception_handler() позволяют напрямую получать текущие обработчики ошибок и исключений:

// Обработчик ошибок $handler = function (int $errno, string $errstr, ?string $errfile, ?int $errline) { echo "Ошибка: " . $errstr . "\n"; }; var_dump(get_error_handler()); // NULL, пока обработчик не установлен set_error_handler($handler); var_dump(get_error_handler() === $handler); // bool(true), установлен наш обработчик // Обработчик исключений $handler = function (Throwable $ex) { echo "Исключение: " . $ex::class . ": " . $ex->getMessage() . "\n"; }; var_dump(get_exception_handler()); // NULL, пока обработчик не установлен set_exception_handler($handler); var_dump(get_exception_handler() === $handler); // bool(true), установлен наш обработчик

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


Трассировка фатальных ошибок

Фатальные ошибки (такие, как истечение времени выполнения или памяти) теперь содержат обратную трассировку. Это настраивается через новую INI-директиву fatal_error_backtraces, что значительно упростит отладку в сложных случаях. Трассировка стека показывает последовательность вызовов функций, приведших к ошибке, аналогично тому, что выводится при исключениях.


Модуль URI

Модуль URI предоставляет API для безопасного анализа и модификации URI и URL в соответствии со стандартами RFC 3986 и WHATWG URL. Например:

use Uri\Rfc3986\Uri; $uri = new Uri('https://avsoft-web.ru/new-in-php85'); echo $uri->getScheme(); // https echo $uri->getHost(); // avsoft-web.ru

Начиная с PHP 8.5, этот модуль входит в стандартную библиотеку PHP.


Постоянные дескрипторы cURL Share

В отличие от предыдущей функции curl_share_init(), дескрипторы, созданные с помощью curl_share_init_persistent(), живут между PHP запросами. Если повторно вызвать функцию с теми же параметрами, будет получен тот же ресурсный дескриптор:

$share = curl_share_init_persistent([ CURL_LOCK_DATA_DNS, // Кэшируем DNS записи CURL_LOCK_DATA_CONNECT, // Кэшируем TCP/SSL соединения ]); $ch1 = curl_init("https://example.org"); curl_setopt($ch1, CURLOPT_SHARE, $share); $response1 = curl_exec($ch1); curl_close($ch1); // При следующем запросе к тому же домену // DNS и TCP/SSL соединения будут использоваться из кеша $ch2 = curl_init("https://example.org/foo"); curl_setopt($ch2, CURLOPT_SHARE, $share); $response2 = curl_exec($ch2); curl_close($ch2);

Теперь PHP сам управляет ресурсом между запросами, и вам не нужно заботиться о хранении или согласовании дескрипторов.


Clone как функция

Передавая вторым аргументом ассоциативный массив в функцию clone(), можно обновлять свойства во время клонирования объектов. Это позволяет создавать измененные копии без изменения исходного объекта:

class App { public function __construct(public readonly string $env) {} } $prod = new App('production'); $dev = clone($prod, ['env' => 'development']);

Этот подход особенно удобен при работе с иммутабельными объектами и readonly свойствами.


Замыкания в константных выражениях

Новая возможность PHP 8.5 позволяет использовать статические замыкания (анонимные функции) в константных выражениях. Константное выражение — это значение, которое должно быть полностью определено во время компиляции. К таким выражениям относятся параметры атрибутов, константы, значения по умолчанию свойств и параметров функций. Пример с пользовательским атрибутом:

#[Validator( static function(string $value): bool { return preg_match('/^[a-z]+$/', $value); } )] class User { public string $username; }

Пример с константой класса:

class Formatter { public const TO_UPPER = static function(string $str): string { return strtoupper($str); }; } echo (Formatter::TO_UPPER)('php'); // PHP

И пример со значением по умолчанию:

function upper_map( array $data, Closure $fn = static function ($x) { return strtoupper($x); } ) { return array_map($fn, $data); } var_dump(upper_map(['a', 'b', 'c'])); // ['A', 'B', 'C']

Однако есть некоторые ограничения. Чтобы использовать замыкания в константных выражениях, они должны быть static, то есть не могут использовать $this или захватывать переменные из окружающей области видимости. Поэтому нельзя использовать use($foo) или стрелочные функции.


Атрибут #[\NoDiscard]

Атрибут #[\NoDiscard] позволяет разработчикам указывать, что возвращаемое значение функции не должно игнорироваться. Добавив атрибут к функции, PHP будет проверять, используется ли возвращаемое значение, и выдавать предупреждение, если это не так:

#[\NoDiscard] function setStatus(int $status): int { // Логика изменения статуса return $result; } setStatus(5); // Warning $result = setStatus(5); // Предупреждения не будет

Такой подход позволит повысить безопасность API, где возвращаемое значение важно, но про него можно легко забыть.


Атрибуты констант

Теперь к константам, объявленным с помощью const, можно добавлять атрибуты:

#[Deprecated(reason: 'Use API_V2_URL instead. This will be removed in v2.0.')] const API_V1_URL = 'https://api.example.com/v1';

Это позволяет указывать метаданные для них. Но следует иметь в виду, что атрибуты не применимы к константам, созданным с помощью define().


Устаревшая функциональность и изменения в обратной совместимости

Альтернативные приведения скалярных типов через (boolean), (integer), (double) и (binary) больше не поддерживаются. Вместо них следует использовать (bool), (int), (float) и (string) соответственно.

$value = (boolean) $foo; // Устаревший синтаксис $value = (bool) $foo; // Современный вариант

Завершение операторов case точкой с запятой вместо двоеточия больше не поддерживается.

switch ($status) { case 1; // Больше не работает echo 'success'; break; } switch ($status) { case 1: // Правильно echo 'success'; break; }

Использование null в качестве смещения массива или при вызове array_key_exists() объявлено устаревшим. Теперь нужно использовать пустую строку.

$array[null] = 'value'; // Устаревшее поведение array_key_exists(null, $array); $array[''] = 'value'; // Современный вариант array_key_exists('', $array);

Теперь при преобразовании NAN в другие типы выдается предупреждение.

$value = (int) NAN; // Warning

Деструктуризация значений, не являющихся массивами (кроме null), с помощью [] или list() теперь также выдает предупреждение.

['a', 'b'] = 'test'; // Warning

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

$value = (int) 6.7; // Warning

Магические методы __sleep() и __wakeup() были помечены как мягко устаревшие. Современный способ управления сериализацией — методы __serialize() и __unserialize(), которые дают больше контроля и предсказуемости.


🐘 Стоит ли обновляться?

PHP 8.5 не является революционным релизом, однако он делает код более безопасным и простым в поддержке, последовательно устраняя исторические недочеты языка.

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

Чтобы избежать неожиданных проблем, перед обновлением важно убедиться в совместимости зависимостей и используемых библиотек.