PHP 8 и развитие языка в 30 вопросах и ответах

в 8:25, , рубрики: php, PHP 8, Блог компании Skyeng, интервью, Программирование, Разработка веб-сайтов

В конце ноября мы провели стрим с Никитой Поповым и Дмитрием Стоговым, ключевыми контрибьюторами ядра PHP. За полчаса мы получили 100+ вопросов и ребята не успели ответить на все. Поэтому я сгруппировал оставшиеся сообщения по темам, отсеял совсем специфические и собрал ответы в текстовом виде. Все острые и холиварные вопросы оставил.

PHP 8 и развитие языка в 30 вопросах и ответах - 1

Готовя ответы, по многим пунктам я консультировался с Никитой и другими активными участниками сообщества. Кстати, в эту субботу, 27 февраля, мы проводим новый стрим! Будет пара докладов, несколько дискуссий, интересные гости и возможность задать новые вопросы. Читайте те, что под катом и подключайтесь, чтобы задать новые.

Планируется ли дальнейшее развитие type hinting? Например, для сигнатур функций.

Простор для улучшений, безусловно, есть. Со времени стрима появились Enum RFC и соответственно возможность их использовать в декларациях типов.

Из того что обсуждалось:

  • Intersection Types RFC — обсуждался несколько раз, вот тут есть немного контекста.
  • Дженерики — см. ниже.
  • Тайпхинты для Callable — тут было несколько RFC: Typesafe callable, Callable prototypes, Functional interfaces. То есть запрос есть, но пока не было удачного RFC.
  • Алиасы типов — обсуждалось в контексте юнион типов, но пока без отдельного RFC.

Конкретных планов по этим идеям пока нет.

Частый вопрос — «будет ли асинхронный PHP»?

Мы получили 13 вопросов за время ноябрьского стрима, вот что именно спрашивали люди

Появится ли когда-нибудь неблокирующий ввод/вывод?

Будет ли добавлена какая-то асинхронность в php — имеется в виду встроенная в ядро.

Как оцениваете github.com/amphp/ext-fiber, какая вероятность пройти rfc?

Будет ли РНР асинхронным?

Планируется ли добавление функционала Promise`ов?

Будет ли как то развиваться многопоточное/асинхронное программирование в дальнейших версиях? Есть конкретные планы?

LibUV. В каком состоянии интеграция LibUV в ZendEngine? И будет ли она?

Будет ли event loop-ы на РНР конкурентные с Нодой?

Планируется ли реализация такого же event loop как в javascrypt?

Theoretically, is it possible, to implement light threads, like coroutines in Kotlin<3, via JIT and FFI? Or is it possible to create an async mechanism using JIT?

Есть ли будущее у асинхронного пхп (reactphp, swoole, asyncphp)?

Будет ли движение php в сторону асинхронщины?

Планируется ли внедрение асинхронности и/или многопоточности в следующих версиях языка?

Смотря что понимать под «асинхронным PHP».

Писать неблокирующий код на PHP можно уже сейчас с помощью Amp, ReactPHP, Workerman.

Активно обсуждается предложение по файберам RFC и готова реализация. Если оно будет принято, то это упростит работу с пакетами типа ReactPHP и Amp. Подробнее было на канале PHP Digest.

Вот примеры, как может выглядеть аналог async/await в PHP 8.1 + Amp v3 и на ReactPHP.

Кроме того, еще есть Swoole. Это расширение для PHP, в котором реализовано уже все для создания полностью асинхронных приложений, в том числе драйверы БД, а также корутины и каналы. И даже использование стандартных функций для работы с IO (например file_get_contents()). В 2017 я его не рекомендовал, но сейчас он оброс отличной экосистемой и готов для использования в продакшне.

Есть более минималистичное подмножество Swoole: swow. Теоретически, у него есть даже шансы быть включенным в ядро. Но пока об этом рано говорить. Дождемся результатов голосования по файберам.

Что по дженерикам в PHP?

Мы получили 5 вопросов за время ноябрьского стрима, вот что именно спрашивали люди

Будут ли в php generic`и?

Планируется ли реализация дженериков для PHP? Когда она может увидеть свет?

Дженерики. Будут ли, и когда. Полноценные, или фейковые, без рантайм проверки.

Ну когда же будут дженерики?

Есть ли в планах дженерики?

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


Дальше перевод ответа Никиты на Reddit.

Для тех, кто не слишком знаком, есть три основных способа реализации дженериков:

  • Type-erasure (стираемые): Дженерики просто удаляются и Foo<T> становится Foo. Во время выполнения дженерики ни на что не влияют, и предполагается, что проверки типов осуществляются на каком-то предварительном этапе компиляции/анализа (прим. Python, TypeScript).
  • Reification (реификация): Дженерики остаются в рантайме и могут быть на этом этапе использованы (и в случае PHP, могут быть проверены в рантайме).
  • Monomorphization (мономорфизация): С точки зрения пользователя, это очень похоже на реификацию, но подразумевает, что для каждой комбинации аргументов дженериков генерируется новый класс. То есть, Foo<T> не будет хранить информацию что, класс Foo инстанциирован с параметром T, а вместо этого будут созданы классы Foo_T1, Foo_T2, …, Foo_Tn специализированный для данного типа параметра.

> Вы сказали, что мономорфизированные дженерики ухудшат производительность, а reified дженерики потребуют много изменений во всей кодовой базе.

Основная проблема мономорфизации — это не столько производительность, (теоретически она хороша, и даже в случае reifieid дженериков может быть смысл мономорфизировать “горячие” классы по причинам производительности.), сколько использовании памяти. Для каждой комбинации типов аргументов должен быть сгенерирован отдельный класс. Если это также предполагает дублирование всех методов (которые могут зависеть от аргументов типов), то для этого потребуется много памяти.

Мономорфизация как главная стратегия реализации не имеет смысла в PHP. Она важна для таких языков, как C++ или Rust, где возможность специализировать код для определенных типов имеет большое значение для производительности (и даже в этом случае размер кода остается большой проблемой). В PHP мы не получим от него достаточной выгоды в плане производительности, чтобы оправдать накладные расходы по памяти (опять же, когда речь идет об общей мономорфизации). Тем более что непонятно, как можно кэшировать мономорфизированные методы в opcache (из-за требований иммутабельности).

Единственная причина, по которой мономорфизация была предложена в качестве стратегии реализации, заключается в том, что она упростит реализацию наивной модели дженериков. Предполагается, что нам просто нужно сгенерировать новые классы для всех комбинаций, а остальным частям ядра вообще ничего не нужно знать о дженериках. Однако эта идея ломается, если учесть вариативность дженерик параметров (Traversable<int> — это Traversable<int|string>), поскольку такие отношения не могут быть смоделированы без непосредственного знания дженерик параметров.

> Не было заметно особо отзывов по исследованию дженериков, которое вы опубликовали на GitHub. Были ли закулисные разговоры об этом, или это все?

Нет, не было особо разговоров об этом. В последний раз, когда я говорил об этом с Дмитрием, его позиция была (неудивительно) жестким "нет". Слишком много сложностей добавляется, потенциально слишком большое влияние на производительность.

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

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

function test(): List<int> {
    // We don't want to write this:
    return new List<int>(1, 2, 3);
    // We want to write this:
    return new List(1, 2, 3);
}

Мы точно не хотели бы, чтобы людям на PHP пришлось писать больше типов, чем на современном статически типизированном языке, таком как Rust. Однако, я не совсем понимаю, как вывод типов для дженерик параметров в настоящее время может быть интегрирован в PHP. В первую очередь из-за очень ограниченного представления о кодовой базе, которая есть у компилятора PHP (он видит только один файл за раз). Приведенный выше пример очевиден, но почти все, что выходит за его рамки, кажется быстро переходящим в "невозможное".

Это оставляет меня в конфликте с поддержкой дженериков в PHP, и это также является причиной, по которой я не настаивал на обсуждениях этой темы. Я сам не уверен, что это хорошая идея.

> Вы рассматривали стираемые дженерики, как это делает Python?

And that leaves us with the cowards way out…

Во-первых, я думаю, что неправильно говорить, что у Python есть стираемые дженерики. У Python все типы стираемые – и это все меняет. Если вся ваша модель типов заключается в том, что аннотации типов игнорируются во время выполнения и проверяются отдельным статическим анализатором, то это отдельный самодостаточный подход. Это как phpdoc в PHP.

Наша проблема в том, что у нас уже есть реализация типизации, которая работает путем валидации типов во время выполнения. Делать часть типов валидированными во время выполнения, и часть из них полностью игнорируемыми, было бы неконсистентно (хотя я думаю, что неконсистентность — это своего рода девиз PHP...).

Хуже того, в PHP даже не будет встроенного валидатора типов, а проблема будет делегирована стороннему инструменту статического анализа, такому как psalm, phpstan или phan (или, по крайней мере, как я понимаю). Это означает, что тип может быть нарушен по умолчанию, и вы должны пойти еще добавить что-то, чтобы предотвратить это.

Еще хуже (черт возьми, насколько хуже может быть?), у нас в PHP есть разделение типов на слабое и строгое. Типы в PHP – это не просто декларации типов, они также могут действовать как приведение типов!

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

class StringList {
    public function add(string $value) { $this->data[] = $value; }
}
$list = new StringList;
$list->add(42);
var_dump($list); // ["42"]
class List<T> {
    public function add(T $value) { $this->data[] = $value; }
}
$list = new List<string>;
$list->add(42);
var_dump($list); // [42]

Даже strict_types=1 не полностью спасает нас от этого, потому что преобразования int->float по-прежнему разрешены.

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

Sorry, I just don't have a good answer for you :(


Есть попытка стандартизировать синтаксис и семантику дженериков в PHP: ссылка. Пока она довольно сырая и на ранней стадии обсуждения.

Что можно сделать, чтобы разработка PHP стала доступной более широкому кругу разработчиков?

Под этим заголовком мы объединили 3 оригинальных вопроса с ноябрьского стрима

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

Какой нужен минимум знаний для разработки ядра и вирт машины?
Как попасть к вам в команду? Спасибо за ответ!

Когда можно будет писать php на php?

Ядро PHP в обозримом будущем останется на C. Поэтому если есть желание контрибьютить, то придется с ним разобраться. Никита обновляет PHP Internals book, в котором описаны внутренности ядра.

И есть статья Никиты PHP 7 Virtual Machine и даже перевод — она актуальна и из нее можно почерпнуть все самое важное для старта.

Что касается расширений, то тут есть потенциал для развития. Никита и Дмитрий занимаются исследованием возможности писать расширения на PHP. Ждем результатов этого исследования.

Планируется ли открыть внутреннее API PHP наружу через FFI, чтобы писать экстеншены на самом языке? С учетом отказа от PECL в PHP 8 вопрос становится актуальным.

Такого плана нет.

Задепрекейчен сам инструмент pecl, который использовался для установки расширений, потому что он использовал PEAR. А расширения, конечно же, не задепрекейчены.

Можно ли будет подключать к PHP модули на других языках, кроме C? Я видел примеры подключения Rust через FFI — и это очень криво выглядит.

Теоретически это возможно, но технически никто не занимался написанием нужных интерфейсов для FFI.

В качестве альтернативы FFI есть возможность подключения wasm модулей: wasmerio/wasmer-php.

Какое будущее у FFI?

Кажется, что в FFI уже есть все, чтобы его использовать. Пока использование не особо активно.

Убили короткий тэг. Чем руководствовались, какой в этом смысл?

Если речь про <?, то его не убили. Было горячее обсуждение RFC, но в итоге решили, что в ближайшие 5 лет трогать его не будут.

Зачем добавляют mixed type?

Есть два основных аргумента в его пользу:

— mixed сигнализирует о том, что тип не забыли указать, просто он не может быть уточнён,
— mixed часто фигурирует в документации PHP.

Подробнее можно прочитать в предложении RFC.

Подписывайтесь на канал PHP Digest, чтоб узнавать про такие вещи первыми. Про mixed была заметка еще в мае 2020.

Будет ли развитие рефлексии? Изменение проперти типов?

Изменения типов свойств, то есть ReflectionProperty::setType, и вообще любых изменений классов не будет никогда. Классы неизменяемы — это часть философии языка.

Почему Reflection медленный?

Нет одной вещи из-за которой это медленно, тут набор факторов. Никита его оптимизировал в последних версиях. Но если есть какой-то конкретный случай, то лучше создать баг и Никита постарается разобраться.

Почему php разработчики получают меньше, чем Java разработчик (примерно одного уровня). Или это не так?

Думаю, заработок зависит не столько от языка программирования, сколько от других факторов.

Во-первых, от сложности задач и уровня ответственности, который предполагают эти задачи.

Поскольку на PHP делается очень много простого веба (небольшие сайты, CMS и т. п.), то и средний уровень зарплат возможно ниже.

А во-вторых, от особенностей рынка.

Профессии на хайпе более востребованы, а специалистов меньше, соответственно они дороже. К маргинальным технологиям это тоже относится. Условно Cobol или Perl разработчиков днем с огнем не сыщешь и получают они много. PHP не попадает ни в одну из этих категорий.

Кроме того, что такое “Java и PHP разработчики примерно одного уровня”? Как вы сравниваете?

Почему стоит выбрать PHP, а не Go или Node.js?

Выбирайте, что больше нравится.

PHP это в основном веб-разработка. Сейчас более популярны "универсальные" языки типа Python и JS. Планируется ли расширять зону применения PHP?

PHP, как язык, такой же универсальный как JS или Python. Вопрос в рантаймах, то есть где его можно запускать. Станет ли возможным запускать PHP в браузере, как JS? Не думаю, потому что зачем?

Одним из мотивов для FFI и JIT как раз был потенциал применения PHP в других сферах. Что из этого выйдет — поживем-увидим.

Планируете ли вы интегрировать final свойства в PHP, как, например, immutable data classes в Java?

Идея иммутабельности в том или ином виде постоянно витает в PHP-сообществе. Были разные RFC на эту тему. Скорее всего, что-то будет.

Есть подробное исследование темы от Larry Garfield. И есть черновик RFC по аксессорам свойств, который позволит делать иммутабельные объекты.

Планируется ли уменьшение бюрократии для небольших патчей? Упираюсь в то, что ради мелкого патча просят создать RFC с полным фаршем.

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

Если нужна помощь с оформлением RFC — пишите либо мне pronskiy, либо @Danack. Кстати, можно ознакомиться с его репозиторием c непринятыми RFC github.com/Danack/RfcCodex и документом по этикету RFC.

Почему фичи PHP 8 такие сырые?

Привет, Кирилл serafimarts :-) Жизнь слишком коротка, чтобы закончить хоть что…

  1. Именованные аргументы не гарантируют совместимость на уровне интерфейсов и значительно увеличивают проблемы BC для OS библиотек.

    Есть предложение по атрибуту для задания алиасов #[NamedParameterAlias].

  2. Атрибуты не имеют возможности иерархичной/вложенной декларации и текущий API не позволяет их ввести нормально в будущем.

    См. ниже.

  3. Property Promotion не доделан: Зачем нужны фигурные скобки у конструктора с такими аргументами? Как декларативно их прокинуть в родительский конструктор?

    Не помню, чтоб кто-то поднимал этот вопрос. Почему ты не задал его во время обсуждения RFC?

  4. Почему добавили match, нарушающий дизайн языка? А если добавляются выражения, то где ""$some = foreach (...) => ..."" или ""$some = if(...) => ...""?"

    Видимо, потому, что другие выражения мало кому нужны. Всегда можно создать RFC.

  5. Зачем добавлять union types без возможности их внешней декларации: "type iterable = array | Traversable""? Почему только дизъюнкция и нет конъюнкции типов?

    Алисы типов годная идея, обсуждается, пока без конкретных планов. По поводу конъюнкции — см. ответ в первом вопросе про развитие тайпхинтов.

  6. Зачем костыль со Stringable, но не добавлять такие же неявные имплементации Countable, Serializable, etc...? — Почему утиная типизация только для Stringable?

    Stringable нужен, чтоб можно было использовать объект с __toString() там, где стоит тайпхинт string. C Countable и Serializable такой проблемы нет.

Иногда это выбор между «сделать так» или «вообще никак». В разных RFC голосования склоняется в ту или иную сторону.

Какие перспективы по введению nested attributes?

Ответ есть в самом RFC: Why are nested attributes not allowed?

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

То есть, теоретически поддержку сделать можно, но пока не планируется.

А почему с вводом аннотаций не ввели сразу какую то привязку к функциям или методам из коробки, как в том же питоне?

Это другой концепт. Атрибуты в PHP — это метаданные, а в Python – это декораторы.

Если хочется именно декораторы, возможно, наилучшим решением будет goaop/framework. Пока он, правда, не совместим с PHP 8.

Планируется ли улучшение SPL или поддержки разных структур данных в PHP?

Вот пара вопросов на этот счет от зрителей стрима

Есть какие-то планы по развитию/улучшению SPL в сторону https://github.com/php-ds
Планируется ли добавить в ядро PHP хорошо спроектированные популярные структуры данных: деревья, графы, списки, очереди, множества, кортежи и т.д.
Планируется ли добавление специализированных структур данных (кортежи, множества, деревья т.д.) в ядро?

Есть интерес улучшить эту часть PHP. Из недавнего: обсуждается возможность добавить неймспейс SPL.

Что касается php-ds, то его автор не хотел бы, чтоб расширение мерджили в ядро, потому что в этом случае он был бы привязан к релизному циклу PHP.

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

Да, такие планы есть, более того в каждом релизе что-то делается для этого.

Вот пример из недавнего: Restrict $GLOBALS usage – ограничено использование $GLOBALS, что позволило избавиться от кучи внутренних проверок и упростить кодовую базу. Именно об этом говорил Дмитрий Стогов на стриме отвечая на вопрос: «что стоило бы убрать в следующих версиях PHP».

Планируется ли в php добавлять библиотеки для машинного обучения?

Нет. А в каком языке они есть в ядре?

Можно использовать RubixML/ML или просто специализированные инструменты.

Как вы относитесь к гегемонии Laravel? AR/статик-методы/трейты

Популярность Laravel точно помогает PHP, а значит помогает и всем, кто пользуется языком.

AR/статик-методы — дело вкуса. Про трейты Никиты уже высказался, а на стриме обсудили их вдоль и поперек.

Целесообразно ли поддерживать активно-растущий проект на php 5.6 или начинать понемногу переписывать на php 7 или 8?

Нецелесообразно. Более того, крайне опасно. Лучше активно пофиксить совместимость с PHP 8.0. Не переписывать все на новый лад, а просто сделать возможным запуск минимальными исправлениями. А новые фичи уже делать с использованием новых возможностей.

Есть приведение типов, например int или array, — можно сделать приведение типов к объекту?

Можно.

В php есть довольно старое расширение php SOAP. Будет ли оно как-то развиваться/дополняться?

Расширение очень старое и над ним никто активно не работает. Более того, в нем самое большое число открытых багов из всех расширений PHP.

Если вам нужен SOAP, то лучше использовать юзерленд реализации на PHP, а не расширение.

А с какой версии можно использовать или в typehint? CurlHandle|false

Объединенные типы появились в PHP 8.0.

А для чего добавили $object::class? Теперь будут споры что же использовать get_class() или ::class

Добавили для консистентности. Зачем спорить, если можно использовать только новый вариант? roll_safe.gif

Какое будущее у поддержки альтернатив сред выполнения? GraalVM как пример.

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

Будут ли когда-нибудь в PHP возможность запретить доступ к внутренним классам извне библиотеки? Чтобы библиотека предоставляла доступ только к интерфейсным классам, а внутренние использовать запрещено.

Такая идея возникала RFC Namespace visibility и даже чуть раньше была реализация подобного. Проблема в том, что хотелось бы private/internal на уровне пакетов. А у нас только неймспейсы и поэтому непонятно как это должно работать.

Пока остается использовать PHPDoc тэг @internal.

Будет ли возможность определить, какие трейты использует класс? По аналогии с class_implements

class_uses()

Применение каких новинок PHP 8 будет влиять на снижение производительности?

Почти всех :-) Хоть оно и незначительное. Кроме, разве что, проверки типов когда много используется наследования. Но в PHP 8.1 станет намного лучше благодаря inheritance cache.

Сколько можно выиграть в производительности, если убрать все проверки типов рантайме?

Зависит от приложения. Вот inheritance cache для Symfony дает прирост 8% — это приблизительно и есть оверхед проверки типов.

Ребята, по памяти будут улучшения? как пример двигать sbrk при застоях и больших дырках

Такая проблема действительно может быть. Например, при использовании расширений, которые выделяют память, используя аллокатор операционной системы, а не PHP. Например, так ведет себя libxml. Но как бороться с этим непонятно. Пока решения нет.

Какие компании финансируют развитие php? Неужели новые версии php выпускают энтузиасты безвозмездно?

Прямо: Zend, JetBrains, Microsoft. Косвенно много других, например, MongoDB, Oracle,

Сколько человек работает над ядром пхп?

Фултайм работают трое: Никита Попов (JetBrains) и Дмитрий Стогов (Zend) над ядром, и Christoph M. Becker (Microsoft) над расширениями.

Активное участие принимают многие. Можно посмотреть по статистике контрибьюторов.

Вот облако тегов тех, кто приложил руку в PHP 8.0:
PHP 8 и развитие языка в 30 вопросах и ответах - 2
Картинка от php.watch.

Когда будет PHP 8.1.0?

Новые версии языка выходят каждый год приблизительно в ноябре-декабре. Соответственно, PHP 8.1 ожидается в конце 2021.

p.s. Подключайтесь к стриму в субботу, чтобы узнать больше о состоянии PHP в 2021 году

Автор: Роман Пронский

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js