Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама
Переклади 04 листопада 2026

Спільна мова для PHP: навіщо стандартній бібліотеці SortDirection і Time\Duration

Це переказ колонки Тіма Дюстерхуса (Tim Düsterhus, Tideways) у блозі PHP Foundation від 3 листопада 2026 року. Структура й технічні аргументи - авторові, скорочення - наші. Про самі нововведення PHP 8.6 ми вже писали в огляді «Що нового у PHP 8.6», тут ідеться про мотивацію, дизайн-рішення і про те, що буде далі.

Усі PHP-проєкти, хоч на повноцінному фреймворку, хоч на мікросервісному з ретельно дібраними бібліотеками, хоч у вигляді розширення для CMS, мають одну спільну річ - стандартну бібліотеку PHP. str_replace(), array_map(), DateTimeImmutable чи Uri\Rfc3986\Uri з PHP 8.5 доступні завжди, працюють однаково і означають одне й те саме. Тому стандартна бібліотека - це lingua franca екосистеми: завдяки їй окремі бібліотеки вбудовуються у фреймворки, а розробник переносить досвід з одного проєкту в інший.

Після розширення Random у PHP 8.2, нового DOM API у 8.4 і розширення URI у 8.5 PHP 8.6 поповнює цей словник enum SortDirection і класом Time\Duration. Обидва маленькі, і це навмисно. Автор пояснює, чому їхня цінність набагато більша за розмір.

Кожен винаходить колесо

Коли для поняття на кшталт «скільки минуло часу» чи «в який бік сортувати» немає типу в стандартній бібліотеці, кожен проєкт вигадує власний. Окремо кожне таке рішення має сенс. Але коли їх збирають в одному застосунку, на кожній межі між двома бібліотеками з'являється клей-код, а розробникові доводиться вивчати, яким «діалектом» говорить кожна з них.

Сам PHP тут не виняток. Щоб передати «проміжок часу», стандартна бібліотека використовує:

  • секунди (sleep());
  • мілісекунди (CURLOPT_TIMEOUT_MS);
  • мікросекунди (usleep());
  • наносекунди (hrtime());
  • пару цілих чисел - секунди плюс дробова частина (stream_set_timeout());
  • числа з рухомою комою (microtime(true)).

З напрямком сортування схожа картина. Є цілочисельні константи SORT_ASC і SCANDIR_SORT_ASCENDING, які працюють лише з певними функціями і ніяк не позначені на рівні типів. Для масивів є пари функцій, що відрізняються лише напрямком. Бібліотеки використовують рядки на кшталт 'ASC' або параметри типу bool, а ті, що орієнтуються на PHP 8.1, створили власні enum. Пошук SortDirection на GitHub дав понад 150 різних, взаємно несумісних збігів - і це без enum з іншими назвами, як-от Order у Doctrine.

Два нові слова у словнику

SortDirection - enum рівно з двома варіантами (Ascending і Descending) без жодної поведінки. Він повністю описується чотирма рядками:

enum SortDirection {
  case Ascending;
  case Descending;
}

Написати такий у своїй бібліотеці - дрібниця. Але щоб поєднати кілька бібліотек, кожна з яких має свій SortDirection, потрібні перехідники між однаковими за змістом enum. Оскільки в PHP 8.6 SortDirection доступний завжди, бібліотеки можуть сміливо використовувати його в публічних API, а в інше подання перетворювати лише тоді, коли треба серіалізувати значення для SQL-запиту чи HTTP API:

$query->orderBy('created_at', SortDirection::Descending);

Time\Duration - це проміжок часу, який показав би секундомір: від однієї наносекунди до понад ста років, з наносекундною точністю на всьому діапазоні. Іменовані конструктори прямо називають одиницю, тож більше не треба гадати, у чому параметр $timeout чекає значення - у секундах, мілісекундах чи фазах Місяця. Для читання є властивості ->seconds і ->nanoseconds та окремий прапорець ->negative, без «магічних чисел».

Першим API, яке приймає Time\Duration, став новий polling API з проєкту Streams, що теж входить у PHP 8.6:

$events = $pollContext->wait(Time\Duration::fromMilliseconds(250));

Фундамент для наступних кроків

Time\Duration корисний і сам по собі, але задуманий як перша цеглина нового API для дати й часу, побудованого на можливостях сучасного PHP. Наступна частина вже обговорюється у PHP Internals: RFC Time\Instant і Time\Clock пропонує клас Time\Instant для моментів у часі та інтерфейс Time\Clock.

Саме інтерфейс Clock найцікавіший для тих, хто пише тести. Код, який сам питає системний час, важко тестувати: результат залежить від того, коли запущено тест. Якщо ж такий код отримує годинник ззовні через інтерфейс, у тесті можна підставити свою реалізацію з потрібним моментом часу. Стандартний інтерфейс означає, що бібліотеки й фреймворки зможуть домовитися про одну точку підміни замість кожен свою.

Дві частини API складаються, як шестерні: відстань між двома Time\Instant - це Time\Duration, а щоб зсунути момент у часі, передають Time\Duration.

Чому це варте інвестиції

Enum на чотири рядки і клас із трьома властивостями та кількома методами можна написати самому за пів дня, ні з ким не домовляючись. Навіщо довге обговорення RFC? Автор вважає, що саме така робота окупається найбільше: вона дає екосистемі спільну опору, яка замінює власні реалізації, а не просто ще один спосіб написати те, що вже існує.

Попит був і раніше: понад 150 варіантів enum, кілька бібліотек і розширень із класом-секундоміром. Усі вони з добрих намірів розв'язують ту саму задачу - і всі несумісні між собою. Одне обговорення дизайну в PHP Internals, хоч і дорожче на старті, замінює всі ці зусилля і дає екосистемі те, до чого можна зійтися.

Планування на десятиліття вперед

Для стандартної бібліотеки правильний дизайн важить більше, ніж для будь-якого пакета. Через жорстку обіцянку зворотної сумісності PHP другої спроби майже не буває: щойно щось потрапило у стабільний випуск, навіть найменша несумісна зміна зачіпає тисячі користувачів.

Простори імен дають рідкісну можливість для другої спроби, бо значна частина стандартної бібліотеки з'явилася раніше за них. Новий API може оселитися в порожньому просторі імен, не чіпаючи поведінки старого, а користувачі переходять на нього у власному темпі. Так уже зробили з Random, DOM і URI (Random\*, Dom\* і Uri\* замість mt_rand(), DOM* і parse_url()).

Тому RFC свідомо роблять маленькі кроки з чітко описаним майбутнім обсягом робіт. Кожне сьогоднішнє рішення обмежує наступні, а деякі шляхи може закрити зовсім. Маленький правильний API, спроєктований з думкою про розвиток, легко розширити. Великий, але трохи хибний API муляє десятиліттями.

На практиці це виглядало так. Тім Дюстерхус і Дерік Ретанс (Derick Rethans), мейнтейнер ext/date і підрядник PHP Foundation, хотіли, щоб новий polling API приймав тайм-аут як Time\Duration, а не парою $timeoutSeconds і $timeoutMicroseconds, і встигнути до feature freeze PHP 8.6, після якого сигнатура стала б остаточною. Від першої пропозиції RFC лишалося близько двох місяців.

Невдалий API в одному методі - локальна проблема. А невдалий будівельний блок, який використовуватимуть усюди, розв'язав би малу проблему ціною великої. Тож пропозиція обмежилася двома видами функціональності:

  • тим, у чому автори були впевнені, з перестраховкою;
  • тим, на що спиратимуться майбутні доповнення і що не можна додати пізніше, не зламавши наявних очікувань.

Підтримка від'ємних тривалостей належить саме до другого виду. Якби перша версія Time\Duration вважала тривалість завжди невід'ємною, код почав би на це покладатися, і додати від'ємні значення згодом без поломки вже не вдалося б. Тому прапорець ->negative закладено одразу, а все зручне, але необов'язкове, автори прямо попросили спільноту PHP Internals не обговорювати і залишили на майбутнє. У результаті вийшов клас для загального поняття, корисний уже сьогодні, навіть якщо наступні частини так і не з'являться, і з місцем для Time\Instant та всього, що буде далі.

Як зробити це сталим

Така робота не безкоштовна. Авторам RFC треба дослідити тему, запропонувати дизайн і вести обговорення. Рецензентам - читати RFC, ділитися досвідом і, можливо, втретє сперечатися про назви, поки не дійдуть згоди. Реалізацію треба написати, перевірити і підтримувати ще довго. Автор відкрито пише, що працює в Tideways - компанії-засновниці та срібному спонсорі PHP Foundation, яка оплатила частину його часу на RFC SortDirection, Time\Duration і Time\Instant. А PHP Foundation фінансує розробників, як-от Деріка Ретанса, і це значною мірою пояснює, чому стандартна бібліотека PHP останніми роками стає дедалі кращою.

Що може зробити кожен

  • Спробувати. Тестуйте PHP у період пре-релізів, зосереджуючись на нових можливостях на кшталт Time\Duration, і повідомляйте про знайдені проблеми, щоб нові функції добре себе показали після стабільного випуску.
  • Прийняти. Якщо ви підтримуєте бібліотеку, розширте її API, щоб воно приймало нові типи. Union type у параметрі дозволяє зробити це без несумісних змін - користувачі отримають зрозумілішу термінологію і лишаться на звичних бібліотеках.
  • Вплинути. Долучайтеся до обговорення RFC, наприклад того, що про Time\Instant. Цінна будь-яка думка, велика чи мала.
  • Профінансувати. Якщо на перші три пункти бракує часу, можна оплатити час інших - наприклад, переконати роботодавця стати спонсором PHP Foundation. Кожне покращення самого PHP багаторазово окупається зручнішою розробкою.

Для Laravel-розробників це теж не абстракція: щойно SortDirection і Time\Duration з'являться в API фреймворків і пакетів, на межах між ними поменшає перетворень рядків і чисел туди й назад.

Переклад оригіналу: thephp.foundation
0

Поділитись

Читати в документації

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

Переклади 03 листопада 2026

Як приймати вебхуки в Laravel і не обпектися: підписи, захист від повторів та ідемпотентність

Покроково будуємо надійний приймач вебхуків у Laravel: перевірка HMAC-підпису через hash_equals, вікно часу проти повторного відтворення, унікальний індекс замість перевірки «чи існує», обробка через чергу та ідемпотентне завдання з тестом на справжній підпис.

19
Переклади 03 листопада 2026

Звіт, який зсунувся на три години: правила роботи з часовими поясами в бізнес-застосунках на Laravel

Щоденний звіт про продажі щоранку недораховував замовлення, зроблені між північчю і 03:00. Шість правил, які не дають цій помилці повернутися: UTC для моментів часу, напіввідкриті діапазони замість whereDate(), часовий пояс як IANA-назва в даних і конвертація лише для показу.

15

Вакансії за темою

King Group Нова
Сьогодні

Middle PHP developer

Middle PHP розробник для високонавантаженої веб-платформи Social Casino/Online Casino: розвиток продукту, перехід монолітного проєкту на мікросервіси (Symfony), оптимізація баз даних, написання unit та functional тестів. Стек: PHP 7.4, Symfony 4, Yii, PostgreSQL 14, Redis, RabbitMQ, NGINX. Вимоги: 3-4+ роки продуктового досвіду з PHP, Yii, Symfony, PostgreSQL, розуміння REST API, Git, ООП та SOLID. Досвід з брокерами повідомлень і DDD буде плюсом.

Tech Lead — Fintech

Tech Lead для фінтех-платформи бізнес-витрат і платежів: активна розробка, архітектурні рішення, стабільність продакшену та менторство команди. Ключовий стек: PHP, Laravel/Lumen, MySQL, Redis, Docker, знання JavaScript (Vue.js, React на базовому рівні). Вимоги: розуміння життєвого циклу карткових транзакцій і криптовалют, досвід побудови надійних фінансових систем (баланси, звірка, аудит, безпечні API), DevOps-навички на Linux.

Bewort Нова
Сьогодні

Senior Full-Stack Developer (PHP/Laravel, Vue)

Розробка та розвиток ключових функцій корпоративної платформи на Laravel з обробкою бекенду та фронтенду на Vue. Потрібні глибокі знання внутрішньої архітектури фреймворку, досвід застосування SOLID, DDD, подій і черг, а також досвід роботи зі складними проєктами. Обов'язкове активне використання AI-інструментів для написання коду та англійська не нижче B2. Переваги: досвід із Vue, мультитенантними SaaS, AWS, CI/CD та LLM-інтеграціями.

Пакети за темою

Kalimera

welldigit/kalimera

Interactive installer that scaffolds Laravel applications the Well Digit way.

v1.0.0 16

Bagisto

bagisto/bagisto

Bagisto — це платформа для електронної комерції, побудована на Laravel. Вона надає готове рішення для створення та управління інтернет-магазинами з підтримкою каталогу товарів, замовлень, платежів та клієнтів.

28,325 v2.5.0 13 28