PHP 8.5 вышел 20 ноября 2025 года и стал очередным минорным релизом языка. На момент мая 2026 актуальная стабильная ветка — именно 8.5 (последний патч на эту дату — 8.5.6). Релиз продолжает курс на эргономику кода: меньше вложенных вызовов, меньше ручного копирования объектов, больше встроенных инструментов вместо сторонних библиотек.
Ниже разобраны главные изменения с примерами. Для каждого английского термина в скобках дан перевод.
Pipe-оператор |> (pipe operator — оператор конвейера)
Главная синтаксическая новинка. Оператор |> берёт значение слева и передаёт его как единственный аргумент (single argument — единственный аргумент) функции справа. Цепочка преобразований читается слева направо, а не "изнутри наружу", как при вложенных вызовах.
<?php
declare(strict_types=1);
$input = ' Hello World ';
// Было (before — раньше): вложенные вызовы, читаются изнутри наружу
$result = strtolower(str_replace(' ', '-', trim($input)));
// Стало (after — теперь): конвейер, читается слева направо
$result = $input
|> trim(...) // обрезать пробелы
|> fn ($s) => str_replace(' ', '-', $s)
|> strtolower(...);
// 'hello-world'
Синтаксис trim(...) — это first-class callable (синтаксис вызова как значения), появившийся ещё в 8.1. Если функция принимает несколько аргументов, оборачиваем её в стрелочное замыкание (arrow function — стрелочная функция), чтобы зафиксировать остальные параметры.
Важно: правая сторона должна быть вызываемой (callable — вызываемое), принимающей ровно один аргумент. Это не "магический пайп" из shell — параллелизма (parallelism — параллельное выполнение) здесь нет, всё выполняется последовательно.
clone() с модификацией свойств (clone with — клонирование с изменением)
Раньше для паттерна "wither" (изменяемая копия неизменяемого объекта) приходилось писать отдельный метод и вручную копировать поля, особенно для readonly-свойств (readonly — только для чтения), которые после конструктора менять нельзя. Теперь функция clone() принимает второй аргумент — массив новых значений свойств.
<?php
declare(strict_types=1);
final class Money
{
public function __construct(
public readonly int $amount,
public readonly string $currency,
) {}
}
$price = new Money(amount: 100, currency: 'USD');
// Клон с заменой одного свойства, исходный объект не меняется
$discounted = clone($price, ['amount' => 80]);
echo $discounted->amount; // 80
echo $price->amount; // 100 — оригинал нетронут
Изменения применяются к копии после клонирования, поэтому даже readonly-поля можно переопределить в этом единственном безопасном месте. Это убирает горы шаблонного кода (boilerplate — шаблонный код) в иммутабельных (immutable — неизменяемых) объектах-значениях.
Расширение URI (URI extension — расширение для работы с URI)
В стандартную поставку добавлено встроенное расширение для разбора и нормализации (normalization — приведение к канонической форме) ссылок. Оно поддерживает два стандарта: RFC 3986 (классические URI) и WHATWG URL (правила браузеров). Раньше для надёжного парсинга URL приходилось тянуть сторонние пакеты, потому что старая функция parse_url() некорректно обрабатывала множество краевых случаев (edge cases — пограничные случаи).
<?php
declare(strict_types=1);
use Uri\Rfc3986\Uri;
$uri = new Uri('https://[email protected]:8080/path?q=1#top');
echo $uri->getScheme(); // 'https'
echo $uri->getHost(); // 'example.com'
echo $uri->getPort(); // 8080
echo $uri->getPath(); // '/path'
echo $uri->getQuery(); // 'q=1'
Доступен также класс по стандарту WHATWG (Uri\WhatWg\Url) — он ведёт себя так же, как разбор адреса в браузере, что важно для веб-приложений, которым нужна совместимость с клиентской логикой.
Атрибут #[\NoDiscard] (no discard — нельзя игнорировать)
Атрибут помечает функцию или метод, чьё возвращаемое значение нельзя молча выбрасывать. Если результат вызова не использован (не присвоен, не передан дальше), PHP выдаёт предупреждение (warning — предупреждение). Это страхует от классических ошибок с иммутабельными API, где метод возвращает новый объект, а не меняет текущий.
<?php
declare(strict_types=1);
final class Builder
{
#[\NoDiscard('результат withName() надо использовать — объект иммутабельный')]
public function withName(string $name): static
{
return clone($this, ['name' => $name]);
}
public readonly string $name;
}
$b = new Builder();
$b->withName('Vitalii'); // Warning: возвращаемое значение проигнорировано
$b2 = $b->withName('Vitalii'); // OK — результат сохранён
Если в каком-то месте игнорировать значение действительно нужно осознанно, его можно явно привести к (void) — тогда предупреждение не сработает.
Замыкания в const-выражениях (closures in constant expressions)
Теперь static-замыкания (static closure — статическое замыкание, без привязки к $this) и first-class callables можно использовать там, где раньше допускались только литералы: в значениях констант, в параметрах атрибутов, в значениях по умолчанию.
<?php
declare(strict_types=1);
#[\Attribute]
final class Validate
{
public function __construct(
public readonly \Closure $rule,
) {}
}
final class Form
{
// Замыкание прямо в параметре атрибута — раньше было невозможно
#[Validate(rule: static fn (string $v): bool => $v !== '')]
public string $name = '';
}
Ограничение: замыкание должно быть static (без захвата $this) и без use с внешними переменными — ведь значение вычисляется на этапе компиляции константы, а не во время выполнения.
Прочие полезные функции
PHP 8.5 добавил две давно ожидаемые функции для массивов — дополнение к array_key_first()/array_key_last() из 7.3:
<?php
declare(strict_types=1);
$items = ['a' => 10, 'b' => 20, 'c' => 30];
echo array_first($items); // 10 — первое значение
echo array_last($items); // 30 — последнее значение
Также расширена асимметричная видимость (asymmetric visibility — разная видимость на чтение и запись) на статические свойства, а атрибут #[\Override] (override — переопределение) теперь применим и к свойствам, а не только к методам.