Написано 29 июля 2026 г.

PHP 8.6 выйдет 19 ноября 2026 г. . Он включает в себя применение частичных функций, новый API опроса, комментарии к документации по параметрам функций, множество устаревших функций и многое другое.

  Кстати! Если вы еще не участвовали в опросе о состоянии PHP , возможно, сейчас самое время потратить на него 15–20 минут. Этот опрос является результатом совместных усилий PHP Foundation и JetBrains; наша цель — получить наилучшее представление о «сообществе PHP». В мероприятии уже приняли участие более 8000 разработчиков, но нам бы хотелось видеть больше.


Приложение частичной функции

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

$makeSlug = str_replace(' ', '-', ?);

После создания замыкания вы можете вызвать его так:

$makeSlug('Hello World');

// Hello-World

PFA особенно полезен в сочетании с оператором канала , поскольку оператор канала всегда требует вызываемого объекта ровно с одним параметром.

$output = 'Hello World' 
    |> str_replace(' ', '-', ?)
    |> strtolower(...);

// hello-world

Вы можете прочитать все о применении частичных функций в этом посте .


Свойство только для чтения по умолчанию

С добавлением перехватчиков свойств в PHP 8.4 вы можете определять перехваты свойств в интерфейсах:

interface MigratesUp
{
    public string $name { get; }

    public function up(): QueryStatement;
}

Однако из-за этого изменения свойства только для чтения со значениями по умолчанию во многих случаях будут иметь смысл:

final class CreateBooksTable implements MigratesUp
{
    public readonly string $name = '2026-01-01_create_books_table';
    
    public function up(): QueryStatement
    { /* … */ }
}

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

И именно поэтому теперь разрешены значения по умолчанию для свойств только для чтения!

final class CreateBooksTable implements MigratesUp
{
    // ✅
    public readonly string $name = '2026-01-01_create_books_table';
    
    // …
}

API опроса

Новый API опроса был создан в первую очередь для облегчения внутренней разработки. Такие функции, как PHP-FPM и обработка сигналов в режиме ZTS (Zend Thread Safety), выиграют от использования единой платформы. Однако новый API опроса также доступен пользователю, что может привести к тому, что его будут использовать фреймворки более низкого уровня, такие как ReactPHP или Amp:

use Io\Poll\Context;
use Io\Poll\Event;
use Io\Poll\StreamPollHandle;
use Time\Duration;
 
// Create a poll context with automatic backend selection
$context = new Context();

// Create a non-blocking socket, just like before
$stream = stream_socket_server('tcp://0.0.0.0:8080', $errno, $errstr);
stream_set_blocking($stream, false);

// Wrap that stream in a new `StreamPollHandle` so that it can make use of the new API
$handle = new StreamPollHandle($stream);
 
// Add the handle to the context
$context->add($handle, [Event::Read], ['type' => 'server']);

while (true) {
    // Wait for one second, polling for new events
    $watchers = $context->wait(new Duration::fromSeconds(1));
    
    // …
}

Важно отметить, что этот новый API опроса не привнесет в PHP никаких новых асинхронных функций. Это еще один (и более простой) способ взаимодействия с асинхронными функциями — раньше PHP имел только stream_select()  в качестве опции для мультиплексирования ввода-вывода. Поскольку новый API также работает с несколькими серверными модулями (например, epoll или WSAPoll), если они доступны, производительность будет выше по сравнению с stream_select()  в определенном масштабе.

Новый API опроса также не имеет встроенного цикла событий, поэтому его перенос в абстракцию более высокого уровня по-прежнему остается на усмотрение пользовательских библиотек. Вы также можете посмотреть подробное видео об этом:


Новая функция ограничения

clamp()  уже является довольно распространенной функцией во многих платформах, которая теперь будет встроена в PHP 8.6. Эта функция гарантирует, что заданное значение (числовое или другое) находится в пределах заданной границы. Если нет, возвращается значение ближайшего края.

clamp(10, min: 0, max: 100); // Will return `10`
clamp(101, min: 0, max: 100); // Will return `100`
clamp(-1, min: 0, max: 100); // Will return `0`

clamp()  работает не только с целыми числами. Например строки:

clamp("y", "x", "z") // Will return "y"
clamp("a", "x", "z") // Will return "x"

Или DateTime  объектов:

clamp(
    value: new DateTimeImmutable('2025-01-01'), 
    min: new DateTimeImmutable('2026-01-01'), 
    max: new DateTimeImmutable('2026-12-31'),
); // Will return `DateTimeImmutable('2026-01-01')`

Новый Продолжительность   класс

Добавлен новый класс \Time\Duration  для обозначения продолжительности времени:

use Time\Duration;

sleep(Duration::fromMilliseconds(500));

Класс поставляется с набором методов для выполнения математических операций с длительностью:

$baseDelay = Duration::fromMilliseconds(100);

$baseDelay->add(Duration::fromSeconds(2));

$attempt = 5;
$delay = $baseDelay->multiplyBy(2 ** $attempt);

Вы также можете напрямую сравнить две продолжительности:

if ($durationA < $durationB) {
    /* … */
}

И вы сможете использовать его в таких местах, как новый API опроса:

$watchers = $context->wait(new Duration::fromSeconds(1));

Новые функции отражения isReadable  и isWriteable .

Появились две новые функции, указывающие, доступно ли свойство отражения только для чтения и/или записи. С добавлением перехватчиков свойств в PHP 8.4 имеет смысл иметь эти методы в API отражения PHP:

final class Book
{
    private(set) string $title;
}

$property = new ReflectionProperty(Book::class, 'title');

$property->isReadable(scope: Book::class);
$property->isWriteable(scope: null);

Наиболее важной является переменная $scope , поскольку она определяет, из какой области свойства можно читать или записывать. Например: частное свойство можно прочитать изнутри самого класса, но не снаружи:

$property->isWriteable(scope: Book::class); // true
$property->isWriteable(scope: null); // false

При желании вы также можете передать второй параметр $object . Если вы это сделаете, API отражения сможет определить, установлено ли уже свойство только для чтения или нет, что также определит, доступно ли оно для записи или нет.

final class Book
{
    public readonly string $title;
}

$book = new Book();

$property = new ReflectionProperty(Book::class, 'title');

$property->isWriteable(scope: null, object: $book); // true

$book->title = 'Timeline Taxi';

$property->isWriteable(scope: null, object: $book); // false

Комментарии к документации по параметрам функции

API отражения PHP был расширен методом getDocComment()  в ReflectionParameter  . На практике это означает, что вы можете переписать это:

/** @param Book[] $books */
function store(array $books): void { /* … */ }

Как это:

function store(
    /** @param Book[] */
    array $books,
): void { /* … */ }

Конечно, вы также можете написать более короткую однострочную версию, добавив блок документации по обе стороны от параметра:

function store(/** @param Book[] */ array $books): void { /* … */ }
function store(array $books /** @param Book[] */): void { /* … */ }

Обратите внимание: если комментарий документа идет после параметра, он должен идти перед запятой, отделяющей параметр от следующего:

function store(
    array $books /** valid placement to link to $books */, 
    array $other, /** this one won't be detected */
): void { /* … */ }

Хотя эта функция, вероятно, будет наиболее полезна для статических анализаторов, вы, конечно, можете использовать отражение, чтобы прочитать эти комментарии к документации по параметрам:

$reflection = /* … a method or function reflector */

$parameters = $reflection->getParameters();

$parameters[0]->getDocComment();

Новое перечисление SortDirection 

PHP 8.6 поставляется с новым встроенным перечислением для представления направлений сортировки:

enum SortDirection {
    case Ascending;
    case Descending;
}

Платформы и библиотеки могут по своему усмотрению поддерживать это перечисление во всем, что требует сортировки, а затем сопоставлять SortDirection  со всем, что необходимо в этом контексте. Обратите внимание, что встроенные функции PHP, такие как array_multisort()  или scandir() , пока не поддерживают это перечисление, но планируется сделать это в будущем.


Улучшена безопасность для настроек сеанса по умолчанию

PHP меняет несколько значений настроек ini по умолчанию, чтобы сделать сеансы более безопасными: и session.use_strict_mode , и session.cookie_httponly  по умолчанию будут 1  вместо 0  ; и для session.cookie_samesite  также будет установлено значение Lax  , а не быть установленным вообще. RFC предоставляет обзор того, как эти изменения могут повлиять на ваши проекты , я также перечислю их здесь:

session_use_strict_mode 

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

Приложения, использующие собственный обработчик сеанса, метод validateId()  которого безоговорочно возвращает true, не затрагиваются. Сюда входят общие серверные программы, такие как Redis и Memcached, при использовании обработчиков сеансов php-memcached или phpredis по умолчанию, которые не реализуют validateId()  и поэтому возвращают true.

session.cookie_httponly 

Флаг HttpOnly  применяется браузером. Он предотвращает чтение значения файла cookie сеанса через document.cookie;  и не влияет на то, отправляет ли браузер файл cookie с запросами.

Приложения, которые считывают значение файла cookie сеанса из document.cookie   в JavaScript (например, для встраивания идентификатора в пользовательский заголовок запроса), больше не смогут этого делать. Идентификатор сеанса является учетными данными на стороне сервера и не должен использоваться клиентским кодом. Приложения, которым требуется доступный клиенту токен для корреляции запросов, должны использовать отдельный, явно не HttpOnly токен CSRF, а не сам файл cookie сеанса.

session.cookie_samesite 

С помощью SameSite=Lax  браузер отправляет файл cookie сеанса при запросах одного и того же сайта и при навигации между сайтами верхнего уровня, используя безопасные методы HTTP ( GET   и HEAD   ). Он не отправляет файлы cookie при межсайтовых запросах подресурсов или межсайтовых запросах POST  .

Приложения, которые полагаются на межсайтовый POST  , переносящий файл cookie сеанса — например, инициируемые поставщиком услуг потоки единого входа SAML или устаревшие формы отправки из разных источников — должны либо явно установить SameSite=None; Secure  для этих конечных точек, либо перейти на поток на основе токенов.

Как отмечалось выше, Chrome и Firefox уже применяют Lax   в качестве неявного значения по умолчанию для файлов cookie, отправляемых без атрибута SameSite . Приложения, работающие в этих браузерах, уже подвержены такому поведению; это изменение делает его явным и единообразным для всех браузеров и версий PHP.


Отлаживаемые перечисления

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

enum Status: int
{
    case OK = 200;
    case NOT_FOUND = 404;
    case FOUND = 302;
    case INTERNAL_SERVER_ERROR = 500;
    
    public function __debugInfo() {
		return [__CLASS__ . '::' . $this->name . ' = ' . $this->value];
	}
}
 
var_dump(Status::OK);

// enum(Status::OK) (1) {
//  [0]=>
//   string(16) "Status::OK = 200"
// }

Устаревания

Как обычно, любой второстепенный выпуск PHP сопровождается множеством обновлений: предупреждениями о том, что что-то будет изменено или удалено в будущей основной версии PHP. Хорошо исправить недостатки уже сегодня, прежде чем они станут реальной проблемой в будущем.

Возврат из блока , наконец,  

Возврат из , наконец,   всегда был очень запутанным и приводил к тонким ошибкам. Сейчас это устарело:

function getConfig(): array {
    try {
        return loadConfig();
    } finally {
        return [];
    }
}

Устарело использование , пусть   в качестве идентификатора.

Причиной прекращения поддержки является возможность использовать let   в качестве возможного ключевого слова в будущем:

class let { /* … */ }

function let() {}

Использование устарело:   в качестве идентификатора.

Причиной прекращения поддержки является возможность использования is   в будущем в сочетании с оператором match  :

class is { /* … */ }

function is() {}

Устарело использование пространства имен в качестве имени константы класса.

Мотивация состоит в том, чтобы зарезервировать пространство имен   для будущего синтаксиса, например, это позволит в будущем использовать псевдоконстанту ::namespace , аналогичную ::class .

class Foo {
  const NAMESPACE = '';
}

Устарела возможность называть функцию только для чтения  

readonly   изначально было разрешено в качестве имени функции, поскольку в WordPress была функция с таким же именем. Это было достигнуто с помощью взлома лексера PHP, который сейчас устарел:

function readonly { /* … */ }

Устарело использование _  в качестве псевдонима константы и времени компиляции.

Это следует за прекращением поддержки PHP 8.4, где одно подчеркивание уже устарело для имен классов.

const _ = 1;

Передача объектов, которые интерпретируются как массивы

Некоторые функции, такие как array_walk()  или inflate_init() , принимают объекты вместе с массивами. Внутренний способ реализации может вызвать незначительные ошибки и привести к повреждению памяти. Вот почему такое поведение устарело в PHP 8.6:

$objectInsteadOfArray = new /* … */;

array_walk($objectInsteadOfArray, fn () => /* … */)

Deprecate is_double 

Вместо is_double()  следует использовать is_float() :

if (is_double($value)) {
    /* … */
}

Deprecate is_integer 

Вместо is_integer()  следует использовать is_int() :

if (is_integer($value)) {
    /* … */
}

Deprecate is_long 

Вместо is_long()  следует использовать is_int() :

if (is_long($value)) {
    /* … */
}

Устаревший doubleval  

Вместо doubleval()  следует использовать floatval() :

if (doubleval($value)) {
    /* … */
}

Устаревший $case_insensitive  для определяет функцию  

Поддержка констант, нечувствительных к регистру, давно удалена.

define('MY_CONSTANT', 'value', case_insensitive: true);

Устаревшие is_subclass_of  и is_a , если $allow_string  имеет значение false  

is_subclass_of()  используется для проверки того, является ли имя объекта или класса подклассом какого-либо другого именованного класса/интерфейса. Первым параметром может быть либо объект для проверки, либо имя класса. Третий параметр, $allow_string , определяет, может ли первый параметр быть строкой. Причина, по которой это полезно, заключается в том, что если установлено значение false, строки не будут запускать автозагрузку. Однако если строка задана, когда $allow_string  имеет значение false   , функция всегда будет возвращать false   , даже если класс не нуждается в автозагрузке.

Если разработчик указал, что строки не должны быть разрешены (по умолчанию они разрешены), то передача строк указывает на ошибку, поэтому она устарела.

is_subclass_of(Foo::class, Bar::class, allow_string: false);
is_a(Foo::class, Bar::class, allow_string: false);

Устаревший strcoll  

Эта функция теперь устарела:

strcoll($a, $b);

Устаревший флаг SORT_LOCALE_STRING  для функций сортировки  

sort($array, flags: SORT_LOCALE_STRING);

Устаревшая функция метафона  

Эту функцию можно использовать для определения слов со схожим звучанием. Однако он основан на очень старом алгоритме и поддерживает только английский язык. Вместо этого нам рекомендуется полагаться на более современные реализации пользовательского пространства, такие как noodlesnz/double-metaphone .

Устаревшая настройка ReflectionProperty  со значениями неправильного типа.

Возможность использовать свойство отражения одного класса для установки свойства другого класса устарела:

class Original 
{
    private $property;
}
 
$property = new ReflectionProperty(Original::class, 'property');

Обратите внимание, что $property  относится к Original::$property  . Однако вы можете использовать то же самое свойство отражения для установки значений для других объектов:

class Other {}

$other = new Other();

$property->setValue($other, true);

Устаревший статический вызов через отражение реальных объектов.

И ReflectionMethod::invoke() , и ReflectionMethod::invokeArgs()  принимают необязательный объект при вызове методов экземпляра. Если вы вызываете статический метод, вместо него следует передать null  :

class Book
{
    public static function create() {}
}

$method = new ReflectionMethod(Book::class, 'create');

$method->invoke(null);

Однако вы по-прежнему можете передать объект при вызове статического метода, даже если он ничего не делает. Такое поведение устарело:

$book = new Book();

$method = new ReflectionMethod(Book::class, 'create');

$method->invoke($book); // Only if the method is static

Устаревшие методы ArrayIterator 

Из РФЦ:

Различные методы ArrayIterator существуют только потому, что долгое время они имели общую реализацию с ArrayObject. Большинство этих методов не имеют особого смысла и не позволяют оптимизировать реализацию ArrayIterator.

Эти методы устарели:

ArrayIterator::getFlags()
ArrayIterator::setFlags()
ArrayIterator::asort()
ArrayIterator::ksort()
ArrayIterator::uasort()
ArrayIterator::uksort()
ArrayIterator::natsort()
ArrayIterator::natcasesort()
ArrayIterator::unserialize()
ArrayIterator::serialize()

Deprecate spl_classes 

У spl_classes()  уже давно есть лучшая альтернатива — ReflectionExtension::getClassNames() . Итак, функция теперь устарела:

spl_classes();

// Use this one instead:
new ReflectionExtension('spl')->getClassNames();

Deprecate spl_object_hash 

Вместо spl_object_hash()  следует использовать spl_object_id() .

spl_object_hash($object);

Если вам все еще нужен реальный хеш вместо идентификатора объекта, вы можете сгенерировать его следующим образом:

$hash = $obj
    |> spl_object_id(...)
    |> dechex(...)
    |> str_pad(?, 16, '0', STR_PAD_LEFT)
    |> (fn ($x) => $x . '0000000000000000');

Устаревшие методы, специфичные для csv, в SplFileObject 

Эти методы устарели:

SplFileObject::fgetcsv()
SplFileObject::fputcsv()
SplFileObject::setCsvControl()
SplFileObject::getCsvControl()

В RFC перечислены следующие причины:

Эти API становится все труднее поддерживать из-за исторических проблем проектирования и несоответствий. Введение именованных аргументов еще больше выявило проблемы в конструкции и поведении API.

Функциональность обработки CSV, естественно, не принадлежит SplFileObject, и будущая работа будет лучше обеспечена специальным расширением CSV, обеспечивающим более чистый и удобный в обслуживании API.

Deprecate mysqli::stmt_init 

$statement = $mysqli->stmt_init();
$statement->prepare($sql);

// Instead do this:
$statement = $mysqli->prepare($sql);

Deprecate mysqli_get_charset 

Из РФЦ:

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

Предлагается объявить устаревшей и удалить эту функцию и ее объектно-ориентированный псевдоним `mysqli::get_charset()`, а затем удалить ее без замены. Маловероятно, что какой-либо проект PHP до сих пор использует эту функцию, а если и использует, то, вероятно, не знает, что она возвращает фальсифицированную информацию.

Устарела передача недействительных обработчиков сеансов в session_set_save_handler .

Из РФЦ:

Пользовательские обработчики сеансов не обязаны реализовывать методы, которые гарантировали бы, что расширение сеанса будет корректно работать в отношении параметра session.use strict mode INI. Это важно, поскольку значение по умолчанию для него было изменено в RFC «Настройки по умолчанию для конфигурации безопасного сеанса», и его никогда не следует отключать.

Для четкого определения поведения необходимы методы create_sid() и validateId().

Устаревшие возвращаемые значения из конструкторов и деструкторов.

Хотя раньше это было технически разрешено, оператор возврата из конструктора или деструктора никогда не имел никакого смысла, поскольку обе функции можно вызывать только в контекстах, где вы все равно не можете сохранить это возвращаемое значение. Вот почему такое поведение теперь устарело:

class Book
{
    public function __construct() 
    {
        return 1;
    }
    
    public function __destruct() 
    {
        return 0;
    }
}

Вот и все! Этот список все еще может обновляться, поскольку PHP 8.6 все еще готовится к замораживанию функций. Подпишитесь на мою рассылку , чтобы быть в курсе событий!

Также последнее напоминание о том, что вы все еще можете принять участие в опросе Состояние PHP . Этот опрос является результатом совместных усилий PHP Foundation и JetBrains, и наша цель — получить как можно более полную картину «сообщества PHP». Более 8000 разработчиков уже приняли участие, и я надеюсь, что вы тоже сможете принять участие!