- PVSM.RU - https://www.pvsm.ru -
В конце ноября мы провели стрим с Никитой Поповым и Дмитрием Стоговым, ключевыми контрибьюторами ядра PHP. За полчаса мы получили 100+ вопросов и ребята не успели ответить на все. Поэтому я сгруппировал оставшиеся сообщения по темам, отсеял совсем специфические и собрал ответы в текстовом виде. Все острые и холиварные вопросы оставил.
Готовя ответы, по многим пунктам я консультировался с Никитой и другими активными участниками сообщества. Кстати, в эту субботу, 27 февраля, мы проводим новый стрим [1]! Будет пара докладов, несколько дискуссий, интересные гости и возможность задать новые вопросы. Читайте те, что под катом и подключайтесь, чтобы задать новые.
Простор для улучшений, безусловно, есть. Со времени стрима появились Enum RFC [2] и соответственно возможность их использовать в декларациях типов.
Из того что обсуждалось:
Конкретных планов по этим идеям пока нет.
Будет ли добавлена какая-то асинхронность в php — имеется в виду встроенная в ядро.
Как оцениваете github.com/amphp/ext-fiber [9], какая вероятность пройти 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 [10] и готова реализация. Если оно будет принято, то это упростит работу с пакетами типа ReactPHP и Amp. Подробнее было на канале PHP Digest [11].
Вот примеры, как может выглядеть аналог async/await в PHP 8.1 + Amp v3 [12] и на ReactPHP [13].
Кроме того, еще есть Swoole [14]. Это расширение для PHP, в котором реализовано уже все для создания полностью асинхронных приложений, в том числе драйверы БД, а также корутины и каналы. И даже использование стандартных функций для работы с IO (например file_get_contents()
). В 2017 я его не рекомендовал [15], но сейчас он оброс отличной экосистемой и готов для использования в продакшне.
Есть более минималистичное подмножество Swoole: swow [16]. Теоретически, у него есть даже шансы быть включенным в ядро. Но пока об этом рано говорить. Дождемся результатов голосования по файберам.
Планируется ли реализация дженериков для PHP? Когда она может увидеть свет?
Дженерики. Будут ли, и когда. Полноценные, или фейковые, без рантайм проверки.
Ну когда же будут дженерики?
Есть ли в планах дженерики?
Короткий ответ: большинство контрибьюторов хотят, но пока нет нормального способа их реализовать в PHP. Не стоит надеяться, что в ближайшее время их добавят в ядре.
Для тех, кто не слишком знаком, есть три основных способа реализации дженериков:
Foo<T>
становится Foo
. Во время выполнения дженерики ни на что не влияют, и предполагается, что проверки типов осуществляются на каком-то предварительном этапе компиляции/анализа (прим. Python, TypeScript).
Foo<T>
не будет хранить информацию что, класс Foo
инстанциирован с параметром T
, а вместо этого будут созданы классы Foo_T1, Foo_T2, …, Foo_Tn
специализированный для данного типа параметра.
> Вы сказали, что мономорфизированные дженерики ухудшат производительность, а reified дженерики потребуют много изменений во всей кодовой базе.
Основная проблема мономорфизации — это не столько производительность, (теоретически она хороша, и даже в случае reifieid дженериков может быть смысл мономорфизировать “горячие” классы по причинам производительности.), сколько использовании памяти. Для каждой комбинации типов аргументов должен быть сгенерирован отдельный класс. Если это также предполагает дублирование всех методов (которые могут зависеть от аргументов типов), то для этого потребуется много памяти.
Мономорфизация как главная стратегия реализации не имеет смысла в PHP. Она важна для таких языков, как C++ или Rust, где возможность специализировать код для определенных типов имеет большое значение для производительности (и даже в этом случае размер кода остается большой проблемой). В PHP мы не получим от него достаточной выгоды в плане производительности, чтобы оправдать накладные расходы по памяти (опять же, когда речь идет об общей мономорфизации). Тем более что непонятно, как можно кэшировать мономорфизированные методы в opcache (из-за требований иммутабельности).
Единственная причина, по которой мономорфизация была предложена в качестве стратегии реализации, заключается в том, что она упростит реализацию наивной модели дженериков. Предполагается, что нам просто нужно сгенерировать новые классы для всех комбинаций, а остальным частям ядра вообще ничего не нужно знать о дженериках. Однако эта идея ломается, если учесть вариативность дженерик параметров (Traversable<int> — это Traversable<int|string>), поскольку такие отношения не могут быть смоделированы без непосредственного знания дженерик параметров.
> Не было заметно особо отзывов по исследованию дженериков [18], которое вы опубликовали на 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?
Ядро PHP в обозримом будущем останется на C. Поэтому если есть желание контрибьютить, то придется с ним разобраться. Никита обновляет PHP Internals book [20], в котором описаны внутренности ядра.
И есть статья Никиты PHP 7 Virtual Machine [21] и даже перевод [22] — она актуальна и из нее можно почерпнуть все самое важное для старта.
Что касается расширений, то тут есть потенциал для развития. Никита и Дмитрий занимаются исследованием возможности писать расширения на PHP. Ждем результатов этого исследования.
Такого плана нет.
Задепрекейчен сам инструмент pecl, который использовался для установки расширений, потому что он использовал PEAR. А расширения, конечно же, не задепрекейчены.
Теоретически это возможно, но технически никто не занимался написанием нужных интерфейсов для FFI.
В качестве альтернативы FFI есть возможность подключения wasm модулей: wasmerio/wasmer-php [23].
Кажется, что в FFI уже есть все, чтобы его использовать. Пока использование не особо активно.
Если речь про <?, то его не убили. Было горячее обсуждение RFC [24], но в итоге решили, что в ближайшие 5 лет трогать его не будут.
Есть два основных аргумента в его пользу:
— mixed сигнализирует о том, что тип не забыли указать, просто он не может быть уточнён,
— mixed часто фигурирует в документации PHP.
Подробнее можно прочитать в предложении RFC [25].
Подписывайтесь на канал PHP Digest [11], чтоб узнавать про такие вещи первыми. Про mixed была заметка [26] еще в мае 2020.
Изменения типов свойств, то есть ReflectionProperty::setType
, и вообще любых изменений классов не будет никогда. Классы неизменяемы — это часть философии языка.
Нет одной вещи из-за которой это медленно, тут набор факторов. Никита его оптимизировал в последних версиях. Но если есть какой-то конкретный случай, то лучше создать баг и Никита постарается разобраться.
Думаю, заработок зависит не столько от языка программирования, сколько от других факторов.
Во-первых, от сложности задач и уровня ответственности, который предполагают эти задачи.
Поскольку на PHP делается очень много простого веба (небольшие сайты, CMS и т. п.), то и средний уровень зарплат возможно ниже.
А во-вторых, от особенностей рынка.
Профессии на хайпе более востребованы, а специалистов меньше, соответственно они дороже. К маргинальным технологиям это тоже относится. Условно Cobol или Perl разработчиков днем с огнем не сыщешь и получают они много. PHP не попадает ни в одну из этих категорий.
Кроме того, что такое “Java и PHP разработчики примерно одного уровня”? Как вы сравниваете?
Выбирайте, что больше нравится.
PHP, как язык, такой же универсальный как JS или Python. Вопрос в рантаймах, то есть где его можно запускать. Станет ли возможным запускать PHP в браузере, как JS? Не думаю, потому что зачем?
Одним из мотивов для FFI и JIT как раз был потенциал применения PHP в других сферах. Что из этого выйдет — поживем-увидим.
Идея иммутабельности в том или ином виде постоянно витает в PHP-сообществе. Были разные RFC на эту тему. Скорее всего, что-то будет.
Есть подробное исследование [27] темы от Larry Garfield. И есть черновик RFC по аксессорам свойств [28], который позволит делать иммутабельные объекты.
Давайте конкретные примеры. RFC требуются для изменений в синтаксисе языка или при поломке обратной совместимости. Очень много изменений проходит обычными пул-реквестами [29] без RFC.
Если нужна помощь с оформлением RFC — пишите либо мне pronskiy [30], либо @Danack [31]. Кстати, можно ознакомиться с его репозиторием c непринятыми RFC github.com/Danack/RfcCodex [32] и документом по этикету RFC [33].
Привет, Кирилл serafimarts [34] :-) Жизнь слишком коротка, чтобы закончить хоть что…
Есть предложение [35] по атрибуту для задания алиасов #[NamedParameterAlias]
.
См. ниже.
Не помню, чтоб кто-то поднимал этот вопрос. Почему ты не задал его во время обсуждения RFC?
Видимо, потому, что другие выражения мало кому нужны. Всегда можно создать RFC.
Алисы типов годная идея, обсуждается, пока без конкретных планов. По поводу конъюнкции — см. ответ в первом вопросе про развитие тайпхинтов.
Stringable
нужен, чтоб можно было использовать объект с __toString()
там, где стоит тайпхинт string
. C Countable
и Serializable
такой проблемы нет.
Иногда это выбор между «сделать так» или «вообще никак». В разных RFC голосования склоняется в ту или иную сторону.
Ответ есть в самом RFC: Why are nested attributes not allowed? [36]
Вложенность атрибутов означает, что определение атрибута будет в аргументе к другому атрибуту. Это намеренно не разрешено, потому что аргумент атрибута это константное AST. Это понятный и стандартный синтаксис. Разрешение вложенных атрибутов потенциально может привести к конфликтам в будущем, а также усложняет для пользователей понимание этого нового контекста, который ведет себя иначе, чем другие части языка.
То есть, теоретически поддержку сделать можно, но пока не планируется.
Это другой концепт. Атрибуты в PHP — это метаданные, а в Python – это декораторы.
Если хочется именно декораторы, возможно, наилучшим решением будет goaop/framework [37]. Пока он, правда, не совместим с PHP 8.
Есть интерес улучшить эту часть PHP. Из недавнего: обсуждается [39] возможность добавить неймспейс SPL.
Что касается php-ds [38], то его автор не хотел бы [40], чтоб расширение мерджили в ядро, потому что в этом случае он был бы привязан к релизному циклу PHP.
Да, такие планы есть, более того в каждом релизе что-то делается для этого.
Вот пример из недавнего: Restrict $GLOBALS usage [41] – ограничено использование $GLOBALS, что позволило избавиться от кучи внутренних проверок и упростить кодовую базу. Именно об этом говорил Дмитрий Стогов на стриме [42] отвечая на вопрос: «что стоило бы убрать в следующих версиях PHP».
Нет. А в каком языке они есть в ядре?
Можно использовать RubixML/ML [43] или просто специализированные инструменты.
Популярность Laravel точно помогает PHP, а значит помогает и всем, кто пользуется языком.
AR/статик-методы — дело вкуса. Про трейты Никиты уже высказался, а на стриме [44] обсудили их вдоль и поперек.
Нецелесообразно. Более того, крайне опасно. Лучше активно пофиксить совместимость с PHP 8.0. Не переписывать все на новый лад, а просто сделать возможным запуск минимальными исправлениями. А новые фичи уже делать с использованием новых возможностей.
Можно [45].
Расширение очень старое и над ним никто активно не работает. Более того, в нем самое большое число открытых багов из всех расширений PHP.
Если вам нужен SOAP, то лучше использовать юзерленд реализации на PHP, а не расширение.
Объединенные типы появились в PHP 8.0 [46].
Добавили для консистентности. Зачем спорить, если можно использовать только новый вариант? roll_safe.gif
Никита и Дмитрий не планируют этим заниматься. Но есть другие люди, возможно кто-то и сделает что-то подобное. В частности, есть концепт для GraalVM [47].
Такая идея возникала RFC Namespace visibility [48] и даже чуть раньше была реализация подобного [49]. Проблема в том, что хотелось бы private/internal на уровне пакетов. А у нас только неймспейсы и поэтому непонятно как это должно работать.
Пока остается использовать PHPDoc тэг @internal
.
class_uses() [50]
Почти всех :-) Хоть оно и незначительное. Кроме, разве что, проверки типов когда много используется наследования. Но в PHP 8.1 станет намного лучше благодаря inheritance cache.
Зависит от приложения. Вот inheritance cache для Symfony дает прирост 8% — это приблизительно и есть оверхед проверки типов.
Такая проблема действительно может быть. Например, при использовании расширений, которые выделяют память, используя аллокатор операционной системы, а не PHP. Например, так ведет себя libxml. Но как бороться с этим непонятно. Пока решения нет.
Прямо: Zend, JetBrains, Microsoft. Косвенно много других, например, MongoDB, Oracle,
Фултайм работают трое: Никита Попов (JetBrains) и Дмитрий Стогов (Zend) над ядром, и Christoph M. Becker (Microsoft) над расширениями.
Активное участие принимают многие. Можно посмотреть по статистике контрибьюторов [51].
Вот облако тегов тех, кто приложил руку в PHP 8.0:
[52]
Картинка от php.watch [52].
Новые версии языка выходят каждый год приблизительно в ноябре-декабре. Соответственно, PHP 8.1 ожидается в конце 2021.
Автор: Роман Пронский
Источник [53]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/361897
Ссылки в тексте:
[1] новый стрим: https://phpcommunity.ru/brave-new-2021
[2] RFC: https://wiki.php.net/rfc/enumerations
[3] RFC: https://wiki.php.net/rfc/intersection_types
[4] тут: https://externals.io/message/110310#110317
[5] Typesafe callable: https://wiki.php.net/rfc/typesafe-callable
[6] Callable prototypes: https://wiki.php.net/rfc/callable-types
[7] Functional interfaces: https://wiki.php.net/rfc/functional-interfaces
[8] в контексте юнион типов: https://wiki.php.net/rfc/union_types#long_type_expressions
[9] github.com/amphp/ext-fiber: https://github.com/amphp/ext-fiber
[10] RFC: https://wiki.php.net/rfc/fibers
[11] PHP Digest: https://t.me/phpdigest
[12] Amp v3: https://github.com/amphp/amp/tree/v3
[13] на ReactPHP: https://github.com/trowski/react-fiber/blob/master/examples/http-client.php
[14] Swoole: https://github.com/swoole/swoole-src
[15] В 2017 я его не рекомендовал: https://www.youtube.com/watch?v=n6Iasl6bx4M
[16] swow: https://github.com/swow/swow
[17] ответа Никиты: https://www.reddit.com/r/PHP/comments/j65968/ama_with_the_phpstorm_team_from_jetbrains_on/g83skiz/?context=3
[18] исследованию дженериков: https://github.com/PHPGenerics/php-generics-rfc/issues/45
[19] ссылка: https://github.com/DaveLiddament/php-generics-standard
[20] PHP Internals book: https://www.phpinternalsbook.com/
[21] PHP 7 Virtual Machine: https://www.npopov.com/2017/04/14/PHP-7-Virtual-machine.html
[22] перевод: https://habr.com/ru/company/badoo/blog/327068/
[23] wasmerio/wasmer-php: https://github.com/wasmerio/wasmer-php
[24] RFC: https://wiki.php.net/rfc/deprecate_php_short_tags_v2
[25] RFC: https://wiki.php.net/rfc/mixed_type_v2
[26] была заметка: https://t.me/phpdigest/147
[27] подробное исследование: https://peakd.com/hive-168588/@crell/object-properties-and-immutability
[28] RFC по аксессорам свойств: https://wiki.php.net/rfc/property_accessors
[29] обычными пул-реквестами: https://github.com/php/php-src/pulls?q=is%3Apr+is%3Aclosed+sort%3Aupdated-desc
[30] pronskiy: https://habr.com/ru/users/pronskiy/
[31] @Danack: https://github.com/Danack
[32] github.com/Danack/RfcCodex: https://github.com/Danack/RfcCodex
[33] документом по этикету RFC: https://github.com/Danack/RfcCodex/blob/master/rfc_etiquette.md
[34] serafimarts: https://habr.com/ru/users/serafimarts/
[35] предложение: https://wiki.php.net/rfc/named_parameter_alias_attribute
[36] Why are nested attributes not allowed?: https://wiki.php.net/rfc/attributes_v2#why_are_nested_attributes_not_allowed
[37] goaop/framework: https://github.com/goaop/framework
[38] https://github.com/php-ds: https://github.com/php-ds
[39] обсуждается: https://externals.io/message/113141
[40] автор не хотел бы: https://github.com/php-ds/ext-ds/issues/156
[41] Restrict $GLOBALS usage: https://wiki.php.net/rfc/restrict_globals_usage
[42] говорил Дмитрий Стогов на стриме: https://www.youtube.com/watch?v=QSszmWIrRyw&t=6289
[43] RubixML/ML: https://github.com/RubixML/ML
[44] на стриме: https://www.youtube.com/watch?v=xoEPNiMtVps
[45] Можно: https://www.php.net/manual/en/language.types.object.php#language.types.object.casting
[46] в PHP 8.0: https://www.php.net/releases/8.0/ru.php#union-types
[47] концепт для GraalVM: https://github.com/abertschi/graalphp
[48] RFC Namespace visibility: https://wiki.php.net/rfc/namespace-visibility
[49] реализация подобного: https://github.com/php/php-src/pull/947
[50] class_uses(): https://www.php.net/manual/en/function.class-uses.php
[51] статистике контрибьюторов: https://github.com/php/php-src/graphs/contributors?from=2020-01-05&to=2021-01-21&type=c
[52] Image: https://php.watch/articles/php80-posters
[53] Источник: https://habr.com/ru/post/543794/?utm_source=habrahabr&utm_medium=rss&utm_campaign=543794
Нажмите здесь для печати.