<? phpukraine ЕКОСИСТЕМА
⌕Пошук по платформі
PHP · ЩО НОВОГО

Що нового в PHP 8.5

  1. 01Pipe-оператор |>: значення проходить ланцюжок функцій зліва направо, без вкладених викликів.
  2. 02Clone with: копія обʼєкта з новими значеннями властивостей, зокрема readonly, одним виразом.
  3. 03Розширення URI за RFC 3986 і WHATWG, #[\NoDiscard], array_first() і стек викликів у фатальних помилках.
СТАТУС Активна підтримка
Реліз
20 листопада 2025
Останній патч
8.5.11
Активна підтримка до
31.12.2027
Безпека до
31.12.2029
НОВІ МОЖЛИВОСТІ · 5

Нові можливості

1.1 · RFC

Pipe-оператор |>

Оператор |> бере значення зліва і передає його єдиним аргументом у callable справа. Ланцюжок перетворень читається в порядку виконання, а не зсередини назовні, і не потребує проміжних змінних. Стрілочну функцію всередині ланцюжка треба брати в дужки.

+ PHP 8.5
$slug = $title
    |> trim(...)
    |> strtolower(...)
    |> (fn (string $s) => str_replace(' ', '-', $s));
− PHP 8.4
$slug = str_replace(' ', '-', strtolower(trim($title)));
1.2 · RFC

Clone with

clone тепер можна викликати як функцію з другим аргументом: масивом властивостей, які треба змінити в копії. Для readonly-класів це прибирає стару незручність, коли wither доводилось писати через new self(...) з переліком усіх полів. Видимість враховується, тож readonly-властивість так змінюється лише зсередини класу.

+ PHP 8.5
public function withAmount(int $amount): self
{
    return clone($this, ['amount' => $amount]);
}
− PHP 8.4
public function withAmount(int $amount): self
{
    return new self($amount, $this->currency);
}
1.3 · RFC

Розширення URI

Нове вбудоване розширення uri дає два парсери: Uri\Rfc3986\Uri за RFC 3986 і Uri\WhatWg\Url за стандартом WHATWG, яким користуються браузери. Обидва незмінні, мають гетери й with-методи, а невалідну адресу відкидають: конструктор кидає Uri\InvalidUriException, parse() повертає null. parse_url() нічого не валідує і охоче розбирає те, чому не можна вірити.

+ PHP 8.5
use Uri\Rfc3986\Uri;

$host = Uri::parse($link)?->getHost();
− PHP 8.4
$parts = parse_url($link);
$host = $parts['host'] ?? null;
1.4 · RFC

#[\NoDiscard] і (void)

Атрибут позначає функцію чи метод, результат якого не можна просто викинути. Якщо виклик стоїть окремою інструкцією, PHP видає Warning. Найчастіше це рятує від методу незмінного обʼєкта, чий результат забули присвоїти. Свідомо відмовитися від результату можна приведенням (void).

+ PHP 8.5
#[\NoDiscard('метод повертає нове замовлення')]
public function withStatus(string $status): self { /* … */ }

(void) $order->withStatus('paid'); // свідомо ігноруємо
− PHP 8.4
$order->withStatus('paid');
// нове замовлення мовчки загубилось
1.5 · RFC

Стек викликів у фатальних помилках

Фатальні помилки на кшталт вичерпаної памʼяті, ліміту часу чи несумісної сигнатури раніше повідомляли лише файл і рядок. Тепер до них додається стек викликів, і видно, який код дійшов до проблеми. Керує цим INI-опція fatal_error_backtraces, увімкнена за замовчуванням, а аргументи з #[\SensitiveParameter] у трейс не потрапляють.

+ PHP 8.5
Fatal error: Allowed memory size of 134217728 bytes exhausted
(tried to allocate 20971552 bytes) in /app/src/Report.php on line 31
Stack trace:
#0 /app/src/Report.php(31): str_repeat()
#1 /app/src/ExportJob.php(18): App\Report->build()
#2 {main}
− PHP 8.4
Fatal error: Allowed memory size of 134217728 bytes exhausted
(tried to allocate 20971552 bytes) in /app/src/Report.php on line 31
СИНТАКСИС · 4

Синтаксис

2.1 · RFC

Замикання в константних виразах

У константних виразах тепер дозволені статичні замикання і first-class callable на кшталт is_numeric(...). Найбільше від цього виграють атрибути: правило валідації передається прямо в аргумент, без назви методу рядком. Замикання має бути static і без use, стрілочні функції тут не підтримуються.

+ PHP 8.5
#[Rule(static function (string $value): bool {
    return str_contains($value, '@');
})]
public string $email;
− PHP 8.4
#[Rule('checkEmail')] // метод шукають за назвою
public string $email;
2.2 · RFC

private(set) для статичних властивостей

У PHP 8.4 public private(set) дозволили лише для властивостей обʼєкта. Тепер так оголошується й статична властивість: лічильник чи реєстр читається звідусіль, а змінюється тільки всередині класу, без окремого статичного гетера.

+ PHP 8.5
public private(set) static int $count = 0;
− PHP 8.4
private static int $count = 0;

public static function count(): int
{
    return self::$count;
}
2.3 · RFC

#[\Override] для властивостей

З PHP 8.3 #[\Override] ловив перейменовані методи батька, тепер він працює і з властивостями. Після появи property hooks інтерфейс теж може вимагати властивість. Якщо її перейменують у батьківському класі чи інтерфейсі, клас з #[\Override] одразу впаде з Fatal error замість тихого розходження.

+ PHP 8.5
class Vacancy extends Post
{
    #[\Override]
    public string $title;
    // Fatal error: Vacancy::$title has #[\Override] attribute,
    // but no matching parent property exists
}
− PHP 8.4
class Vacancy extends Post
{
    public string $title; // у Post її вже перейменували на $name
}
2.4 · RFC

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

Атрибути тепер ставляться і на константи, оголошені через const поза класом. Найкорисніший з них #[\Deprecated]: звернення до застарілої константи дає попередження, як виклик застарілого методу. Прочитати атрибути можна через ReflectionConstant. Окремим RFC #[\Deprecated] дозволили і на трейтах.

+ PHP 8.5
#[\Deprecated('використовуйте API_V2')]
const API_V1 = 'v1';
− PHP 8.4
/** @deprecated використовуйте API_V2 */
const API_V1 = 'v1';
ФУНКЦІЇ · 3

Нові функції

3.1 · RFC

array_first() і array_last()

Дві функції, яких бракувало поруч з array_key_first() і array_key_last() з PHP 7.3. Вони повертають саме значення, не чіпають внутрішній вказівник масиву і дають null для порожнього масиву.

+ PHP 8.5
$first = array_first($salaries);
$last = array_last($salaries);
− PHP 8.4
$first = $salaries[array_key_first($salaries)] ?? null;
$last = end($salaries);
3.2 · RFC

get_error_handler() і get_exception_handler()

Раніше поточний обробник можна було дізнатися лише хитрістю: поставити тимчасовий і одразу відновити попередній. Нові функції просто повертають callable або null. Знадобиться бібліотекам і тестам, які загортають чужий обробник.

+ PHP 8.5
$handler = get_error_handler();
− PHP 8.4
$handler = set_error_handler(fn () => false);
restore_error_handler();
3.3 · НОВЕ

Closure::getCurrent()

Статичний метод повертає замикання, яке виконується зараз. Рекурсивній анонімній функції більше не треба передавати саму себе за посиланням через use, і зберігати її у змінну теж не обовʼязково.

+ PHP 8.5
$sum = function (array $node): int {
    return $node['value'] + array_sum(array_map(Closure::getCurrent(), $node['children']));
};
− PHP 8.4
$sum = function (array $node) use (&$sum): int {
    return $node['value'] + array_sum(array_map($sum, $node['children']));
};
ПРОДУКТИВНІСТЬ · 1

Продуктивність

4.1 · ДВИГУН

OPcache завжди в збірці

OPcache тепер компілюється в PHP так само, як date, pcre чи random, і вимкнути його при збірці вже не можна. Рядок zend_extension=opcache з php.ini треба прибрати. Вмикають і вимикають кеш як раніше, через opcache.enable і opcache.enable_cli.

+ PHP 8.5
; php.ini
opcache.enable=1
− PHP 8.4
; php.ini
zend_extension=opcache
opcache.enable=1
БЕЗПЕКА · 1

Безпека

5.1 · RFC

FILTER_THROW_ON_FAILURE

З цим прапорцем filter_var() і споріднені функції кидають Filter\FilterFailedException на невалідному значенні. Зникає плутанина, коли false означає і помилку, і цілком валідний результат FILTER_VALIDATE_BOOL. Поєднати його з FILTER_NULL_ON_FAILURE не можна, це ValueError.

+ PHP 8.5
$age = filter_var($input, FILTER_VALIDATE_INT, FILTER_THROW_ON_FAILURE);
− PHP 8.4
$age = filter_var($input, FILTER_VALIDATE_INT);

if ($age === false) {
    throw new InvalidArgumentException('Вік має бути числом');
}
DEPRECATED

Застаріло

Ще працює, але дає попередження і зникне в одній із наступних версій.

Зворотні лапки `cmd`Аліас shell_exec() застарів. Викликайте shell_exec() явно.
(integer), (boolean), (double), (binary)Неканонічні назви приведень. Пишіть (int), (bool), (float), (string).
case з крапкою з комоюПісля case ставте двокрапку, варіант case 'new'; застарів.
null як ключ масиву$map[null] і array_key_exists(null, …) застаріли. Використовуйте порожній рядок.
$http_response_headerЗмінна з заголовками останнього HTTP-запиту застаріла. Викликайте http_get_last_response_headers().
curl_close(), finfo_close(), imagedestroy()Разом з xml_parser_free() і curl_share_close() нічого не роблять після переходу на обʼєкти. Виклики можна прибрати.
Reflection*::setAccessible()Нічого не робить з PHP 8.1, виклик можна видалити.
BREAKING

Ламає сумісність

Перевірте це до оновлення: такий код перестане працювати або поводитиметься інакше.

Нові Warning при перетвореннях[$a, $b] = 42, (int) з float поза межами int і з NAN тепер дають Warning. Laravel перетворює його на виняток.
#[\Attribute] на абстрактному класіНа абстрактному класі, інтерфейсі, трейті чи enum це тепер помилка компіляції. Раніше Error зʼявлявся лише в newInstance().
disable_classesINI-опцію видалено, вона ламала припущення двигуна. Рядок у php.ini більше нічого не вимикає.
new Directory()Directory став непрозорим обʼєктом, як ресурс. Створюйте його лише через dir().

Як оновитися

0 / 5