10 сентября 2026 вышел PHP 8.6.0beta3. Это уже не «набросок RFC», а конкретный снимок ветки: язык получил частичное применение функций, clamp(), класс Time\Duration, отдельный Poll API и пачку практичных правок в стримах, сессиях и криптографии.
Это всё ещё beta. На прод ставить рано: баги ещё правят, а сигнатуры отдельных API могут чуть сдвинуться до GA (ориентир — 19 ноября 2026). Зато смотреть уже стоит — особенно если вы пишете Laravel-сервисы, очереди, интеграции и CLI-утилиты.
- Частичное применение функций
- clamp()
- Time\Duration
- Io\Poll: современный polling
- Readonly-свойства с значениями по умолчанию
- Стримы, TLS и ошибки I/O
- Сессии: безопаснее из коробки
- Мелочи, которые реально пригодятся
- Что уже deprecated
- Что это значит для Laravel
- Как попробовать beta
1. Частичное применение функций
Главное языковое изменение 8.6. Вы вызываете функцию, но вместо части аргументов ставите ? или ... — и получаете Closure, а не результат. Это логичное продолжение first-class callables из PHP 8.1 (strtoupper(...)) и хорошо стыкуется с pipe-оператором из 8.5.
<?php
$greet = str_replace('hello', 'hi', ?);
echo $greet('hello world'); // hi world
$titles = ['hello php', 'hello laravel'];
$mapped = array_map(str_replace('hello', 'hi', ?), $titles);
// ['hi php', 'hi laravel']
Плейсхолдеры:
?— ровно один аргумент, который заполнят позже;...— «остальные аргументы как есть».
<?php
function discount(int $percent, float $price, bool $taxInclusive = true): float
{
$net = $price * (1 - $percent / 100);
return $taxInclusive ? $net : $net * 1.2;
}
$minus20 = discount(20, ...);
$minus20(1000); // 800
$minus20(1000, false); // 960
$onlyPrice = discount(15, ?, false);
$onlyPrice(200); // 204
Вместе с |> это убирает лестницу одноразовых fn():
<?php
$names = [' alice ', 'BOB', 'carol'];
$normalized = $names
|> array_map(trim(...), ?)
|> array_map(strtolower(...), ?);
// ['alice', 'bob', 'carol']
Практика: PFA копирует типы, значения по умолчанию и атрибуты вроде
#[SensitiveParameter]. Для колбэковarray_map/array_filterэто чище, чем ручные стрелочные функции. Не превращайте в головоломку каждую строку: если без?читается хуже — оставьте обычный вызов.
2. clamp()
Функция, которую в проектах копировали десятки раз: «если меньше минимума — минимум, если больше максимума — максимум».
<?php
clamp(1, 0, 3); // 1
clamp(1, 2, 5); // 2
clamp(4, 1, 3); // 3
$opacity = clamp($request->integer('opacity'), 0, 100);
$retry = clamp($attempt * 250, 250, 5_000);
Если $min > $max или в границы передали NAN, будет ValueError. Для пагинации, процентов, рейт-лимитов и UI-слайдеров это ровно то, что нужно.
3. Time\Duration
DateInterval умеет «2 месяца» — а месяцы разной длины. Для таймаутов, backoff и stopwatch это плохая модель. Time\Duration — readonly-класс «яичного таймера»: фиксированные секунды + наносекунды, без таймзон и календарных чудес.
<?php
use Time\Duration;
$timeout = Duration::fromMilliseconds(500);
$backoff = Duration::fromSeconds(1)->multiplyBy(2); // 2 секунды
$limit = Duration::fromIso8601DurationString('PT1H30M');
if (Duration::compare($timeout, $backoff) < 0) {
$wait = $backoff;
}
$poll->wait($timeout);
Фабрики: fromSeconds(), fromMilliseconds(), fromMicroseconds(), fromNanoseconds(), fromMinutes(), fromHours(), fromIso8601DurationString(). Операции иммутабельны: add(), sub(), multiplyBy(), divideBy(), negate(), absolute(). Сравнения <, === работают; арифметика через + — нет, только методы. Переполнение бросает Time\TimeException.
Важно: ISO-строка только с time-компонентой (
PT...).P1Dи «месяц» сюда не входят — это сознательно, чтобы таймаут всегда означал одно и то же число наносекунд.
4. Io\Poll: современный polling
stream_select() жив, но это старый select(): потолок дескрипторов, линейный рост стоимости, нет epoll/kqueue. В 8.6 появился Io\Poll — обёртка над epoll (Linux), kqueue (BSD/macOS), WSAPoll (Windows) и запасным poll().
Это не полноценный event loop вроде Revolt/AMPHP. Это низкоуровневый wait по нескольким стримам. Фреймворки смогут опереться на один бэкенд, а вам — написать простой TCP/WebSocket-сервер без ext-uv.
<?php
use Io\Poll\Context;
use Io\Poll\Event;
use Io\Poll\StreamPollHandle;
use Time\Duration;
$poll = new Context();
$server = stream_socket_server('tcp://127.0.0.1:8080');
stream_set_blocking($server, false);
$poll->add(new StreamPollHandle($server), [Event::Read], ['role' => 'accept']);
while (true) {
foreach ($poll->wait(Duration::fromSeconds(1)) as $watcher) {
if ($watcher->hasTriggered(Event::Read)) {
// accept / fread / fwrite
}
}
}
В beta3 Context::wait() принимает Time\Duration (не пару «секунды + микросекунды» из раннего RFC) и отклоняет слишком большой $maxEvents.
5. Readonly-свойства с default
Раньше readonly без конструктора нельзя было инициализировать значением по умолчанию. В 8.6 можно:
<?php
final class FeatureFlags
{
public readonly bool $darkMode = false;
public readonly int $rolloutPercent = 0;
}
final readonly class ListQuery
{
public function __construct(
public string $q = '',
public int $page = 1,
public int $perPage = 20,
) {}
}
Для DTO и конфигов меньше пустого конструктора. После clone-with нетронутые readonly-поля остаются заблокированными — это правка поверх PHP 8.5, а не новая семантика clone.
6. Стримы, TLS и ошибки I/O
Здесь 8.6 выглядит как «наконец навели порядок», а не как игрушка.
- Stream errors API. Классы
StreamException,StreamError, enum’ы режима/кода, функцииstream_last_errors()/stream_clear_errors(), опции контекстаerror_mode,error_store,error_handler. Вместо «warning где-то в логе» можно ловить типизированную ошибку. - Быстрое копирование.
php_stream_copy_to_stream_ex()используетsendfile,splice,copy_file_range,TransmitFile. - Сокетные опции контекста: keepalive (
so_keepalive,tcp_keepidle, …),so_reuseaddr,so_linger, а в beta3 — ещёso_rcvbufиso_sndbuf. - TLS. Session resumption, внешний PSK, TLS 1.3 0-RTT / early data, статус
WANT_READ/WANT_WRITE, AES-SIV,$salt_lengthдля RSA-PSS вopenssl_sign()/openssl_verify().
<?php
$ctx = stream_context_create([
'socket' => [
'so_keepalive' => true,
'tcp_keepidle' => 60,
'so_rcvbuf' => 262144,
'so_sndbuf' => 262144,
],
'ssl' => [
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
],
]);
7. Сессии: безопаснее из коробки
Дефолты, которые давно стоило включить:
session.use_strict_mode = 1session.cookie_httponly = 1session.cookie_samesite = Lax
Плюс: SessionHandler::validateId() реально работает, поэтому strict mode применяется к встроенному хендлеру. Объект сессии без create_sid()/validateId() — deprecated. Невалидные SameSite, lifetime и NUL в path/domain теперь получают warning.
Laravel и так выставляет HttpOnly/SameSite в большинстве приложений. Проверьте кастомные
SessionHandlerи легаси-проекты на чистом PHP: смена дефолтов может «внезапно» починить cookie — или сломать странный кросс-доменный логин, который жил на пустом SameSite.
8. Мелочи, которые реально пригодятся
| Изменение | Зачем |
|---|---|
json_decode пишет место ошибки | Колонка/позиция в сообщении, а не абстрактный syntax error |
SortDirection enum | Явное направление сортировки вместо магических int |
pack()/unpack(): < и > | Endianness в формате, без платформенных сюрпризов |
Uri\Rfc3986\UriBuilder | Сборка URI поверх API 8.5, плюс host/type helpers |
grapheme_strrev() | Реверс строки по графемам, не по байтам |
IntlNumberRangeFormatter | «1–3 кг», «10–20 €» с учётом локали |
mysqli_quote_string() | Экранирование без устаревшего real_escape-ритуала |
ZipArchive::openString() | Открыть ZIP из строки в памяти |
| EXIF из WebP | exif_read_data() больше не только JPEG/TIFF |
gmp_prevprime(), gmp_powm_sec() | Крипто-арифметика без самодельных циклов |
PDO_PGSQL ATTR_CHUNK_SIZE | Выборка большого result set кусками |
| libsodium KEM (X-Wing, ML-KEM768) | Post-quantum обмен ключами, если собрали с libsodium 1.0.22 |
trim() режет и \f | Form-feed в дефолтном наборе |
array_intersect() быстрее | Бесплатный выигрыш на больших массивах |
<?php
try {
json_decode('{ "ok": true, }', flags: JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
// В 8.6 в тексте есть позиция ошибки — проще найти лишнюю запятую
logger()->warning($e->getMessage());
}
$binary = pack('n<', 0x1234); // little-endian 16-bit
[$value] = unpack('n<', $binary);
9. Что уже deprecated
8.6 продолжает зачистку алиасов 90-х и сомнительных перегрузок. На beta это warning, на 9.0 — кандидат на удаление.
is_long(),is_integer()→is_int();is_double()→is_float();doubleval()→floatval()- Третий аргумент
define()(case-insensitive константы) - Имя функции
readonly returnвнутриfinally- Объект в
http_build_query()и вarray_walk()/array_walk_recursive()— сначалаget_object_vars() - Объект в фильтрах zlib/bzip2
spl_object_hash()→spl_object_id();spl_classes()→ Reflectionmetaphone(),strcoll(),SORT_LOCALE_STRING- CSV-методы
SplFileObjectи почти все «удобные» методыArrayIterator mysqli_get_charset(),mysqli_stmt_init(), созданиеmysqli_stmtбез SQL- mbregex; объекты в
mb_convert_variables() - Nullable return type у
__debugInfo(); возврат значения из__construct()/__destruct() is_a()/is_subclass_of()со строкой, если$allow_string = false
Отдельно: больше 16 фильтров в php://filter без filter.max_filter_count — тоже deprecated. Если у вас самодельный pipeline из десяти convert.base64-*, проверьте.
10. Что это значит для Laravel
- Пока ничего не ставьте на прод. Laravel официально поедет на 8.6 после GA и зелёного CI.
- PFA упростит колбэки в коллекциях, jobs и pipeline. Pipe
|>уже есть в 8.5 — в 8.6 он становится полезнее. - clamp() заменяет самописные хелперы для page size, retry delay, процентов.
- Duration — хороший кандидат на таймауты HTTP-клиента, очередей и health-check, когда экосистема подтянется.
- Сессии и cookie. Если приложение не на Laravel Session, прогоните сценарии логина: SameSite=Lax и HttpOnly теперь дефолт движка.
- Депрекейты. Пройдитесь по
is_integer,http_build_query($dto), кастомным SessionHandler и Spl-итераторам в легаси-пакетах.
<?php
$page = clamp((int) $request->query('per_page', 20), 1, 100);
$clean = $request->collect('tags')
->map(trim(...))
->filter(filled(...))
->values();
11. Как попробовать beta
# Официальные QA-сборки
https://www.php.net/pre-release-builds.php
https://downloads.php.net/~svpernova09/php-8.6.0beta3.tar.xz
git clone https://github.com/php/php-src.git --depth 1 --branch php-8.6.0beta3
# Docker (тег проверяйте)
docker run --rm php:8.6-rc php -v
Минимальный чеклист перед экспериментами:
- Поднять 8.6 рядом с 8.4/8.5, не вместо.
- Прогнать тесты с
error_reporting=E_ALL— депрекейты всплывут сразу. - Не включать JIT/Opcache «на удачу» в первом прогоне: сначала корректность, потом скорость.
- Смотреть NEWS между beta2 и beta3: там много security-фиксов (Phar UAF, SOAP WSDL, стримы, SimpleXML).
Вывод
PHP 8.6 beta3 — не косметический минор. Частичное применение делает колбэки человеческими, clamp() и Time\Duration закрывают дыры, которые все латали хелперами, Poll API и stream errors двигают I/O ближе к тому, что давно есть в Go/Node, а новые дефолты сессий чуть меньше оставляют дыр «из коробки».
До GA используйте как песочницу. Если нужен аудит готовности проекта к 8.6 или план миграции Laravel-стека — напишите мне в Telegram @rootseo или через страницу контактов.
Комментарии
Комментарии появляются после модерации.
Опубликованных комментариев пока нет. Будьте первым.