Кілька тижнів тому я опублікував свій вішліст для PHP на 2026 рік. Найбільшу увагу привернув пункт про «PHP Editions». Давайте розберемося, чому це може докорінно змінити майбутнє мови.
Що таке Editions?
Термін «edition» (редакція) кілька років тому запропонував Нікіта Попов, надихнувшись Rust editions. Це спосіб розвивати мову, не зупиняючись через проблеми зворотної сумісності:
Іноді мові необхідні зміни, що порушують зворотну сумісність... Rust вирішує це за допомогою редакцій. Такі зміни впроваджуються лише в наступну редакцію. Оскільки перехід на нову редакцію є добровільним (opt-in), існуючі проєкти (crates) не відчують змін, доки розробники явно не вирішать мігрувати.
Іншими словами: Editions дозволяють впроваджувати ламаючі зміни за бажанням розробника.
У Rust редакція вказується у файлі Cargo.toml (аналог нашого composer.json):
[package] name = "Tempest" version = "0.1.0" edition = "2024"
Кожен пакет у Rust може мати власну редакцію. Різні пакети в межах одного проєкту можуть використовувати різні редакції та без проблем працювати разом. Деякі аспекти цього підходу легко адаптувати для PHP, інші — ні. Розглянемо все по черзі: спочатку потенціал ламаючих змін за запитом, а потім — технічні варіанти реалізації в PHP.
Навіщо щось ламати?
«Хіба ми не можемо просто... нічого не ламати?» Звісно, PHP робить усе можливе для збереження зворотної сумісності. Це не завжди вдається, але сьогодні автоматизовані інструменти зробили оновлення PHP надзвичайно простим. Попри це, статистика Packagist свідчить, що близько 50% PHP-проєктів працюють на застарілих версіях. Приблизно стільки ж популярних Open Source пакетів досі підтримують неактуальні версії PHP. Минулого року PHP подовжив період безпекової підтримки застарілих версій ще на рік, що лише зменшило мотивацію до оновлення.
PHP тримається за зворотну сумісність не просто так — це дає екосистемі стабільність і робить мову надійним вибором. Наприклад, звіт GitHub State of the Octoverse 2025 показує, що позиції PHP залишаються стабільними вже багато років:

Але за стабільність доводиться платити. PHP стає все важче розвивати та перетворювати на сучасну мову. Вимоги до мов програмування у 2025 році відрізняються від тих, що були у 2000-му. Опитування JetBrains показує, що значна частина розробників розглядає можливість переходу на Go, Python або Rust паралельно з PHP або замість нього. Це не обов'язково погано, але це сигнал: PHP має куди рости.

Ось влучна думка, якою поділився Нікіта Попов під час роботи над PHP: > Я вважаю, що впровадження концепції Editions для PHP є надзвичайно важливим. У нас є довгий список проблем, які ми не можемо і ніколи не зможемо вирішити через обмеження зворотної сумісності без можливості добровільної міграції (opt-in).
Отже, навіщо нам «щось ламати»? Щоб рухати мову вперед сучасно і в розумні терміни.
Довгий список проблем
Що саме мав на увазі Нікіта під «списком проблем»? Ось кілька ідей, які він пропонував:
- Явна передача за посиланням (explicit pass-by-reference), де і під час виклику, і під час визначення функції потрібно вказувати посилання.
- Суворі оператори (Strict operators), які змушують усі оператори використовувати суворе порівняння.
- Покращена інтерполяція рядків для довільних виразів, наприклад:
$string = "foo #{1 + 1} bar". - Нарешті, Нікіта згадував відмову від динамічних властивостей, що згодом було реалізовано без Editions.
Останній приклад особливо цікавий. Динамічні властивості стали deprecated у PHP 8.2 і можуть бути видалені у PHP 9.0. Щоб впоратися з цим, додали атрибут #[AllowDynamicProperties]. Але це створило нову проблему: тепер сам цей атрибут колись доведеться видаляти. Це «косметичне» рішення додало головного болю, якого можна було б уникнути за допомогою Editions. Якби розробники могли самі активувати ламаючу зміну, атрибут був би непотрібним.
Ось ще кілька функцій, які могли б бути опціональними:
- Вимкнення перевірки типів під час виконання (runtime type checker) для коду, який уже перевірено статичними аналізаторами. Це могло б підвищити продуктивність.
- На базі попереднього пункту — можливість нарешті впровадити повноцінні Generics.
- Експериментальні функції: те, що точно з'явиться в мові, але потребує року реального тестування перед фінальним релізом.
Ви можете не погоджуватися з окремими пропозиціями, але головне тут — сама можливість PHP розвиватися гнучкіше.
Editions чи щось інше?
Я намагаюся частіше вживати термін «ламаючі зміни за запитом» замість «Editions». PHP не варто просто копіювати модель Rust. У Rust усі редакції компілюються в одну версію, що в PHP реалізувати набагато складніше через його інтерпретовану природу.
Але суть Editions — саме у добровільному виборі змін. І найкраща новина в тому, що в PHP уже є механізм для цього! Він існує з часів PHP 4, і ми ледь використовуємо його потенціал. Мова про declare.
Ви напевно знаєте директиву declare(strict_types=1), додану в PHP 7. Це ідеальний приклад: PHP працює як зазвичай, за винятком файлів, де розробник явно увімкнув сувору типізацію. Це і є ламаюча зміна за запитом.
Declares на рівні Namespace
Головний мінус declare — його треба прописувати в кожному файлі. Якщо додати більше прапорців, початок кожного файлу перетвориться на хаос:
<?php declare(strict_types=1); declare(strict_operators=1); declare(runtime_type_checks=0); declare(generics=1);
Це незручно. Але рішення є: можливість оголошувати директиви на рівні простору імен (namespace). Нікіта Попов працював над цим ще кілька років тому! Є RFC та навіть Pull Request з початковою реалізацією.
Якби ми повернулися до цієї ідеї, то могли б писати так:
namespace_declare('Tempest\\', [ 'strict_types' => 1, 'strict_operators' => 1, 'runtime_type_checks' => 0, 'generics' => 0, ]);
А ще краще — додати підтримку в Composer, аналогічно до автозавантаження класів:
{
"autoload": {
"psr-4": {
"Tempest\\": "src/"
}
},
"declare": {
"Tempest\\": {
"strict_types": "1",
"strict_operators": "1",
"runtime_type_checks": "0",
"generics": "0"
}
}
}Ми всього в одному кроці (одному RFC) від того, щоб відкрити нові горизонти для розвитку PHP.
Запитання без відповідей
Поза увагою залишається багато деталей. Наприклад, чи варто робити щорічні Editions (як у Rust), чи використовувати окремі прапорці функцій? Підхід Rust простіший для розуміння, але гнучкість declare дає більше можливостей.
Також важливо визначити: чи будемо ми підтримувати старі редакції вічно, чи в якийсь момент нова редакція ставатиме стандартом для наступної мажорної версії мови?
Я планую не лише писати про це в блозі. Моя мета — обговорити ці ідеї з членами PHP Foundation. Я готовий допомогти відродити RFC про namespaced declares і розробити фреймворк для майбутніх «opt-in» можливостей мови.
А що ви думаєте: ви за цілісні щорічні Editions чи за гнучкі налаштування окремих функцій? Пишіть у коментарях або долучайтеся до обговорення в Discord.