Вийшов реліз мови програмування PHP 8.1: називаємо ключові оновлення

Розробники представили реліз мови програмування PHP 8.1. Працювали над оновленнями вони близько року. Нова гілка включає серію нових можливостей, а також кілька змін, які порушують сумісність. Розповідаємо детальніше, як оновилася ця популярна мова програмування.

Ключові покращення в PHP 8.1

Насамперед, додано підтримку перерахувань (enum), наприклад, замість класу з константами тепер можна використовувати таку конструкцію:

enum Status {

     case Pending;

     case Active;

     case Archived;

   }

   class Post

   {

       public function __construct(

           private Status $status = Status::Pending;

       ) {}

       public function setStatus(Status $status): void

       {

        // …

       }

   }

   $post->setStatus(Status::Active);

Також додана підтримка легковагових потоків, які називаються файберами (Fiber) і які дають можливість керувати потоками виконання на низькому рівні. Файбери дозволяють визначати блоки коду, виконання яких може бути призупинено та поновлено за аналогією з генераторами, але з будь-якої позиції стека.

Безпосередньо файбери не забезпечують одночасне виконання потоків і вимагають визначення циклу обробки подій, але при цьому дають можливість використовувати один і той самий API в коді, який працює в блокувальному та розблокувальному режимі. Підтримку файберів планується додати у фреймворки Amphp та ReactPHP.

$fiber = новий Fiber(function (): void {

       $valueAfterResuming = Fiber::suspend('after suspending');

           // …

   });

    $valueAfterSuspending = $fiber->start();

    $fiber->resume('after resuming');

Поліпшено реалізацію кешу об’єктного коду (opcache), в якій з’явилася можливість кешування інформації про спадкування класів. Оптимізація дозволила підняти продуктивність деяких програм на 5-8%.

З інших змін, що впливають на продуктивність, відзначається оптимізація роботи JIT, реалізація підтримки JIT для архітектури ARM64 (AArch64), прискорення вирішення імен класів, оптимізація бібліотек timelib і ext/date, підвищення продуктивності серіалізації та десеріалізації, оптимізація функцій get_declar ), strtr(), strnatcmp() та dechex(). Загалом відзначається підвищення продуктивності Symfony Demo на 23%, а WordPress на 3,5%.

Своєю чергою оператора розпакування всередині масивів «...$var», що дозволяє виконувати підстановку існуючих масивів щодо нового масиву, розширили підтримкою рядкових ключів (раніше підтримувалися лише цифрові ідентифікатори). Наприклад, тепер можна використовувати у коді:

$array1 = ["a" => 1];

   $array2 = ["b" => 2];

   $array = ["a" => 0, ...$array1, ...$array2];

   var_dump($array); // ["a" => 1, "b" => 2]

Тепер дозволено використовувати ключове слово «new» в ініціалізаторах. Завдяки цьому можна використовувати об’єкти як значення параметрів за замовчуванням, статичні змінні, глобальні константи та аргументи атрибутів. Також можливе створення вкладених атрибутів.

class MyController {

       public function __construct(

           private Logger $logger = новий NullLogger(),

       ) {}

   }

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

class PostData {

       public function __construct(

           public readonly string $title,

           public readonly DateTimeImmutable $date,

       ) {}

   }

   $post = new Post('Title', /* … */);

   $post->title = 'Other';

   > Error: Cannot modify readonly property Post::$title

А ще реалізовано новий синтаксис для об’єктів, що викликаються (callable) — замикання тепер можна сформувати, викликавши функцію і передавши їй як аргумент значення «...» (тобто для отримання посилання на функцію можна використовувати myFunc(...) замість Closure: :fromCallable(’myFunc’)):

function foo(int $a, int $b) { /* … */ }

   $ foo = foo (...);

   $ foo (a: 1, b: 2);

Крім того, додано повноцінну підтримку перетинів типів (intersection types), що дозволяють створювати нові типи, значення яких повинні відповідати одночасно кільком типам. На відміну від union-типів, що визначають колекції з двох і більше типів, перетини потребують наявності в заповнювальній множині не будь-якого з перерахованих типів, а всіх зазначених типів.

function count_and_iterate(Iterator&Countable $value) {

      foreach ($value as $val) {

          echo $val;

      }

      count($value);

   }

Які ще зміни внесли

У новій версії PHP також з’явився новий тип «never», який можна використовувати для інформування статичних аналізаторів про те, що функція припиняє виконання програми, наприклад, викликаючи виключення або виконуючи функцію exit.

function dd(mixed $input): never

   {

      exit;

   }

Розробники запропонували нову функцію array_is_list, яка дозволяє визначити, що ключі в масиві розташовані в порядку збільшення числових значень, починаючи з 0:

$list = ["a", "b", "c"];

   array_is_list($list); // true

   $notAList = [1 => "a", 2 => "b", 3 => "c"];

   array_is_list($notAList); // false

   $alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

   array_is_list($alsoNotAList); // false

Водночас для заборони перевизначення констант батьківського класу тепер можна використовувати ключове слово «final».

class Foo

   {

       final public const X = "foo";

   }

    class Bar extends Foo

   {

      public const X = "bar";

> Fatal error: Bar::X cannot override final constant Foo::X

   }

Запропоновано функції fsync та fdatasync для примусового збереження змін із дискового кешу.

$file = fopen("sample.txt", "w");

   fwrite($file, "Some content");

   if (fsync($file)) {

       echo "File has been successfully persisted to disk.";

   }

   fclose($file);

Також додано можливість використання префіксів «0o» і «0O» для вісімкових чисел, крім префікса «0», який застосовувався раніше.

016 === 0o16; // true

   016 === 0O16; // true

Віднині вибірково обмежено застосування $GLOBALS, що призведе до порушення зворотної сумісності, але дозволить значно прискорити операції з масивами. У тому числі заборонено запис у $GLOBALS та передача $GLOBALS за вказівником. Аналіз 2000 пакетів показав, що тільки 23 із них зазнають цієї зміни. Наприклад, припинено підтримку таких виразів, як:

$ GLOBALS = [];

   $GLOBALS += [];

   $GLOBALS =& $x;

   $x =& $GLOBALS;

   unset($GLOBALS);

   by_ref($GLOBALS);

Тим часом розробники оголосили застарілими неявні несумісні перетворення чисел із плаваючою комою (float) у цілочисельне уявлення (int), що призводять до втрати точності. Наприклад, зміна застосовна при перетворенні значень ключів масивів, примусовому оголошенні цілочисельних чисел і в операторах, що працюють тільки з цілими числами.

$a = [];

   $a[15.5]; // deprecated, as key value loses the 0.5 component

   $a[15.0]; // ok, as 15.0 == 15

Що ще оновили

Називаємо також ще низку змін у новій версії мови PHP, на які варто звернути увагу:

  • внутрішні методи тепер повинні повертати коректний тип. У PHP 8.1 при поверненні типу, що не відповідає оголошенню функції, з’являтимуться попередження, але в PHP 9.0 попередження хочуть замінити на помилку;
  • продовжено роботу з переведення функцій із використання ресурсів на маніпуляцію об’єктами. На об’єкти переведені функції finfo_* та imap_*;
  • оголошено застарілою передачу значень null як аргументів внутрішніх функцій, помічених як non-nullable. У PHP 8.1 використання конструкцій виду str_contains("string", null) буде призводити до попередження, а в PHP 9 — до помилки;
  • оголошено застарілим програмний інтерфейс Serializable;
  • у багатьох модулях ресурси перетворені в об’єкти (file_info -> finfo в FileInfo, FTPConnection, IMAPConnection, LDAPConnectionResult, PgSqlConnectionResult, PSpellDictionary, GdFont в GD тощо);
  • додано підтримку алгоритмів хешування MurmurHash3 і xxHash.


Раніше повідомлялося, що спільнота розробників популярної мови програмування PHP заснувала нову некомерційну організацію PHP Foundation. Вона відповідатиме за організацію фінансування проєкту, підтримку спільноти та забезпечення процесу розробки.


Нагадаємо, мова програмування PHP посідає 5 місце в нашому ТОП-10 мов програмування в Україні, 2010–2021.


Також можна ознайомитися з рейтингом мов програмування 2021 року за версією DOU.

👍НравитсяПонравилось5
В избранноеВ избранном2
LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Хлопцы, а кто слышал Yii3, когда релизнется?

они сами не знают, да и поезд уже ушёл, Laravel его нишу занял.

но зачем?

8 лет назад написали одну систему еще на Yii1. Спустя года 3 начали пересаживать на Yii2, попутно разрезая монолит на компоненты. Еще черезз полгода поняли, что лучше бы изначально брали Symfony.
Собственно, сейчас рады тому, что много компонентов ядра приложения как раз custom built. Прорабатывает переход на Symfony, все так де разрезая монолит.

так вроде в юйке, есть модули с симфони?symfony.com/projects/yii

Вот я открыл вашу ссылку — вам не кажется, что набор компонентов оч скуден?
Поверьте, вопрос не в том, есть ли там компонент для создания красивого CLI, или поиска файлов на диске. Я несколько раз делал «рука-лицо», когда снова и снова возвращался с событийной модели Yii. Особенно в первой части.

Dependency Injection? Event Dispatcher contracts? Что вы, милейший, зачем?

Хотите глобальный сервис — вот вам components в конфиге. Что-что? Передать параметр в конструктор? Нет, что вы, это для плебеев, мы же вам параметр сервиса будем пихать в свойство объекта. А если вы свойство private/protected, увы, все равно придется прикрутить для него setter метод.

Остановите меня, я могу так долго.

Что только люди не делают, дабы не писать на компилируемых языках )))
Даже VK.com компилят в С-шный код 🤦‍♂️🤦‍♂️🤦‍♂️

Так сейчас мейнстримовых компилируемых раз-два-четыре и обчёлся, в основном JIT-рантаймы, которые уже и в js, и в каком-то виде везде подвозят — php,ruby,python. Беда по перфомансу из-за динамической типизации, ну и у php инициализация на каждый запрос при стандартном стеке (fpm).

у php инициализация на каждый запрос при стандартном стеке (fpm)

Вы только что описали принцип работы PHP как модуля Apache HTTP Server.
PHP-FPM как раз держит N резидентных процессов, общающихся с HTTP сервером посредством FastCGI

Процесс OS не создаётся, делается bootstrap приложения на каждый запрос. Да есть opcache, файловый кеш os, но для не сильно громоздкой api-шки на которую будут сотни-тысячи rps, вся эта инициализация может занимать значительный процент времени.

Roadrunner и reachphp, swoole решают эту проблему. Но подходы другие и в проде очень немногие их используют.

эта инициализация может занимать значительный процент времени

Это c OpCache + отключенная валидация timestamp? Или без них? И о каких процентах мы говорим? О каких порядках RPS?

Потому что такое ощущение, что предметности в комментария нет: «ну, да, можно, но все равно инициализация займет время»? Какое время? Насколько это «усложнило» жизнь вам и вашему проекту или проекту сына маминой подруги?

Мы больше 10 лет «живет» на OpCache + timestamp validation=Off и все более чем хорошо.

P.S. Если же «солью» является отсутствие менеджера глобального стейта приложения, как в NodeJS — то тут да, это «чашка чая для PHP»

И о каких процентах мы говорим?

От почти 0% (при долгих OLAP запросах в админке) до 300% (по запросу к редису+базе с минимумом логики). Конечно opcache и validation=Off, хорошо настроенный пул воркеров в fpm.

Я о том что 50 миллисекунд на бутсрап фреймворка, бывает гараздо дольше чем полезная нагрузка в 15 миллисекунд. И 32 ядерный сервер вместо 500 rps на fpm выдаёт 2000 rps на roadrunner’е.

То что залить деньгами — добавив серверов, прописав их на балансере проблем нет, это понятно. Любой крупный проект — сборная солянка технологий, подходов и костылей workaround’ов.

Но бывают случаи когда fpm (да и вообще php/python/ruby) далеко не самый оптимальный вариант — сбор трафика/аналитики, adTech.

p.s. я вообще не противник php, но runtime golang’а или c# (не синтаксис языков, это уже индивидуально) лучше, как ни крути.

Коментарі про цей реліз від СТО:

«Таке чуство, шо нас бог наказує за шось. Мені так кажеться. Я, наверноє, знаю за шо, но я не можу вам сказати. Ми в церкву ходимо перед кажним релізом. Перед кажним! Перед кажним релізом ходимо в церкву! Перед кажним релізом ходимо в церкву! Кому молитися? Перед кожним релізом весь відділ розробки ходить в церкву!»

www.youtube.com/watch?v=XTA-ANHPjY8

Не допомагає. Кажного разу якась діч вивалюється. Чекаємо на введення нової конструкції у наступній версії: final << go :: $a :: const == ...&$b

Можете розслабитись — головний контріб звалює з пхп і всьо піде на полицю на пару років мінімум
dou.ua/forums/topic/35516

пых так часто хоронили что это уже стало доброй приметой

да ладно вам, за последние пару релизов имхо наиболее нейтральные изменения, ну разве что дичь с

intersection types
intersection types

какая-то дичь

Коли хочеться Trait’ів, але виходить тільки натягнути сову на глобус.

Трайты же есть

Ну а це, наскільки бачу, конструкція, щоби показати, що приймаєш об’єкт, який імплементує всі перераховані трейти.

Не все что можно сделать — нужно делать.
Интерфейсы поддерживают множественное наследование, это всяко логичнее для решения такой дебильный задачи )

Просто копируют синтаксические конструкции из c# / java. Полезность этой штуки небольшая, но хоть backward compatibility не ломает и то хорошо )

Та полезность вообще нулевая + повод говнокодить (чего с пыхом и так в избытке)

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

такие необходимости это как минимум повод проверить не нарушается ли у вас SRP, а если это возникает больше 1 раза в год то повод проверить разработчика на критерии говонокодера )

То есть, вы говорите о том, что ментейнеры PHP заведомо «вкрутили» возможность нарушить SRP, и пример c Iterator&Countable $value притянут за уши? Окей :)

1. Один из нюансов PHP как языка как раз в его пороге входа и том что мейнтеры сознательно идут на некоторые решения которые этот порог держат как минимум (если политкорректно выражаться).
2. решения принимаются голосовательно, а демократия она бессердечная скотина и голосование по этому rfc было НЕ единогласным, при том что обратной совместимости не нарушается вообще никак и с-но голоса против они именно идеологические, считайте что часть мейнтреров со мной согласная ;)
3. возможность нарушить SRP она была всегда и с любыми инструментами, речь о том что rfc ее поощряет, чего у PHP и так с избытком. Причем данный rfc позволяет это сделать максимально «изящно» и «цинично» что позволяет потенциальному говнокодеру даже не понять что он делать что-то плохое и почему это может быть плохое.

Блин, да, перечитав, соглашусь — вы правы: в «legit» случае, такая возможность нужна максимум один раз в год. Во всех остальных случаях не о сверических конях — это явный сигнал о странных вещах

а пример

Iterator&Countable $value

он не просто притянут за уши, он деструктивен )

А если вы нахально хотите нарушить SRP, то следим за руками

Подписаться на комментарии