В последнее время в сообществе разработчиков наблюдается весьма оживленное обсуждение всего того, что касается PHP и его будущего. Что радует — большинство подобных разговоров проходят в позитивном ключе. Популярны дискуссии на тему PHP 6 и того, каким он мог бы выглядеть. Народ задает очень много вопросов об HHVM и её роли в будущем языка и сообщества. Так что позвольте и мне поделиться с вами некоторыми своими мыслями по этому поводу.
Об обратной совместимости
Я считаю, что каждый следующий релиз обязан поддерживать обратную совместимость с предыдущим: 6, 7, 99, «слон-энтузиаст» — называйте как угодно. А теперь я скажу «в основном», поскольку некоторые несовместимости всё же будут иметь место. Но эти несовместимости должны быть обоснованны и контролируемы. Также они должны быть направлены только на пересмотр поведения пограничных случаев и всего такого. Хотя это не означает того, что там не может быть серьезной внутренней реорганизации и стремления к чистоте и простоте вещей. Это означает, что несовместимости не должны чинить препятствий разработчикам.
Такой подход очень легко проверить:
Код, который вы пишете, должен выполняться без проблем и на PHP 5.х, и на PHP 6.х (и любых двух последовательных мажорных релизах).
Почему это важно? Взгляните на переход от PHP 4 к PHP 5. Программистам было достаточно легко писать код, который работал на обеих версиях, хотя на окончательный переход к PHP 5 потребовалось около 10 лет. А представьте, если бы делать это было затруднительно?
Хотя, как выясняется, ничего и представлять не надо. С Python произошло именно это. Первый релиз Python 3 вышел около 5 лет назад. И сегодня, в 2014 году, он все еще задействован не на полную катушку. Не потому, что он плохой, а потому что очень нелегко использовать единый код, который бы работал без проблем на обеих версиях. То есть вы используете либо Python 2, либо тот его функционал, который будет работать в Python 3 (в итоге теряя преимущества обоих). И если нужные вам библиотеки или платформы не имеют версии под Python 3, вам остается либо портировать их самому, либо ну… вам просто не повезло. По факту именно так и происходит.
Я не хочу сказать, что такой подход ошибочен: язык приобретает миллион разных плюшек от подобных изменений. Но, как мне кажется, для сообщества и рядового пользователя такой переход всё же излишне кардинален.
О переписывании движка
Многие люди говорят: надо переписать движок PHP. Несмотря на то, что я определенно вижу в этом плюсы (да, движок весьма замысловат), вынужден задать вопрос: действительно ли это так необходимо? Где фундаментальная собака зарыта? Несомненно, движок PHP имеет архитектурные просчеты, однако по большому счету работает хорошо.
Так что я бы предпочел увидеть переход движка на компонентную основу, разделение его на подсистемы. Сегодня это уже частично сделано. Но я хотел бы увидеть изменения, которые сделали бы движок действительно компонентным. Почему это важно? Потому, что при таком подходе отдельные улучшения смогут внести весомый вклад в развитие движка.
Например, на данный момент самой запутанной частью PHP являются парсер и компилятор. Они настолько тесно связаны и запутаны, что это приводит к массе проблем в разработке. С другой стороны, если бы они были отдельными компонентами движка, тогда что парсер, что компилятор было бы гораздо легче заменить. А их общей частью могло бы быть некое Абстрактное Дерево Синтаксиса (Abstract Syntax Tree). Почему AST? Поскольку это некое общее представление, которое могли бы использовать оба компонента. Да, над этим пришлось бы очень много и хорошо поработать, однако преимущества не заставили бы себя ждать: от последовательного и более предсказуемого синтаксиса до добавления возможности определять собственный синтаксис средствами самого PHP (представьте себе возможность определять DSL в PHP, которые на самом деле являются частью языка).
Так что переписывать заново не нужно. Рефакторить и подчищать.
О переходе стандартной библиотеки к объектно-ориентированному подходу
Некоторые люди предлагают переход стандартной библиотеки PHP к объектно-оритентированному подходу: даже скалярные типы имели бы поведение объектов. То есть вы могли бы написать примерно следующее:
$string = "Foo";
var_dump($string->length); // 3
var_dump($string->toLower()); // string(3) "foo"
// etc
Не думаю, что этому необходимо произойти, хотя, признаюсь, звучит это круто.
Причина проста: скаляры — не объекты. Но, что самое главное, они вообще не относятся к какому бы то ни было типу. PHP полагается на такую систему типов, которая считает, что строки — это целые числа. Гибкость системы заключается также и в том, что любой скалярный тип можно с легкостью привести к другому скалярному типу. Конечно, это не всегда хорошо, ибо из-за этого происходит очень большое количество ошибок.
Однако подобные ситуации могли бы быть разрешены более конкретным поведением. Например, вы могли бы бросить отлавливаемое предупреждение или исключение при попытке «грязного» приведения типов, так что если кто-нибудь попытался бы привести «123abc» к целому числу, то получил бы сообщение о частичной потере данных.
Еще более важным является то, что при наличии такой системы типов вы не можете знать на 100%, какой тип имеет та или иная переменная в данный момент времени. Вы можете предполагать различные варианты, однако что там на самом деле — не известно. Ситуация не шибко изменится даже после приведения типов или если язык будет поддерживать подсказки скалярных типов, поскольку эти типы всё равно позже можно изменить.
Таким образом, всё это означает, что при объектно-ориентированном подходе все скалярные операции должны были быть привязаны ко всем скалярным типам. Что привело бы к объектной модели, в которой скаляры имели бы не только математические методы, но и методы работы со строками. Что за бред…
Становление HHVM
Сегодня, на момент написания этой статьи, я не рекомендую использовать HHVM в продакшне. На то есть несколько причин. Все они известны и не являются фундаментальными. Время покажет, удастся ли их решить, но я на это очень надеюсь.
- HHVM контролируется одной компанией. Не поймите меня неправильно, проблема не в том, что Facebook тратит уйму денег на разработку. Но в том, что проект контролируется компанией, чей бизнес не зависит от того, используете вы HHVM или нет. Одно дело, если бы они осуществляли платную поддержку и сделали HHVM полноценным продуктом. Другое — что сейчас это ни проект с открытым исходным кодом, ни коммерческий проект — нечто среднее. И я был бы весьма напряжен, переводя продакшн на HHVM в такой ситуации.
- HHVM не имеет публичной спецификации, то есть в целом вы будете программировать так же, как под движок Zend. Однако это метод проб и ошибок, поскольку все будет нормально до тех пор, пока вы не попытаетесь поддерживать несколько реализаций. Как разработчик библиотеки я уже прочувствовал это на своей шкуре. С другой стороны, если бы HHVM и PHP пришли в итоге к некоей общей спецификации, многие вещи стали бы гораздо проще...
- HHVM — проект с закрытыми исходниками, хотя и принимает код от сторонних разработчиков (уже хорошо). Однако поток пулл-реквестов и патчей не производит проект с открытым исходным кодом. Ну и где ясность процесса? Где ясность перспектив? Где открытость участия? Где лидерство?
При этом я знаю, что не одинок в своих суждениях. HHVM будет сильным соперником в будущем, но, я считаю, что пока вышеупомянутые вопросы не решены, время HHVM в коммерческом продакшне не настало.
Могут ли PHP и HHVM сосуществовать?
Естественно. Несмотря на то, что некоторые тесты выглядят убедительными, JIT-компиляторы — не магия. Они идут на компромиссы с этим нашим реальным миром: многие тесты выявляют это. Ну, а на самом деле, если вы внимательно посмотрите на подавляющее большинство тестов, вы заметите, что они не исполняют «реальный» код. Стоп-стоп, то есть вы таки сравниваете производительность HelloWorld или генератора чисел Фибоначчи?! Ну, удачи вам, только теперь успокойтесь, пожалуйста, и выкиньте все эти бесполезные результаты.
Позвольте повториться, что тесты, не задействующие реальные системы, бесполезны: это чепуха и даже хуже — они просто опасны.
На практике существуют задачи, с которыми HHVM справится гораздо быстрее PHP. Но в то же время есть задачи, где PHP покажет свою скорость. Единственный способ проверить — протестировать свое приложение.
Но HHVM исполняет мой код как нативный! Как PHP может быть быстрее?
Помните, я сказал, что JIT — не магия? Так вот, это на самом деле так. Вы не можете скомпилировать PHP напрямую, поскольку это интерпретируемый язык программирования. Что означает, что вы не можете знать, какой код стоит в очереди на компиляцию ровно до того момента, как вы не выполните этот код. Так что JIT именно это и делает. Он анализирует исполняемый код и, получив достаточные сведения о нем, генерирует нативный код. Данный процесс не избавлен от издержек, из-за этого HHVM медленна в консоли.
Важнее то, что JIT не генерирует универсальный код. Он генерирует код, в соответствии с условиями, которые существовали на момент создания этого кода. Так что, если ваша функция складывает два целых числа, то такой код мог бы скомпилироваться в простую инструкцию add. Однако компилятор также добавит инструкции проверки параметров на целочисленный тип. И если затем вы передадите в свою функцию не число (что нормально с позиции PHP), одна из проверок даст ложный результат.
Когда проверка дает ложный результат, происходит нечто вроде «аварийного переключения». Проще говоря, движок «отменит» все, что скомпилировал для данного метода и переключится в режим интерпретатора. Проведение такой операции гораздо дороже нежели постоянная работа в режиме интерпретатора.
И это лишь одна причина, по которой JIT-компиляторы — не магия.
Я не хочу, чтобы вы сейчас подумали, будто бы я против JIT-компиляторов. Напротив, для большинства задач они покажут существенный прирост производительности. Но всё же они не идеальны.
Посмотрите на другие сообщества и вы увидите реализации виртуальных машин наряду с JIT-компиляторами. CPython и PyPy — хорошие тому примеры. Стоит также заметить, что Python имеет спецификацию языка, так что вы можете легко сменить одну реализацию на другую.
Но HACK крут!
Hack — новый язык программирования, разработанный Facebook и включенный в HHVM. Грубо говоря, это статически типизированная версия PHP с некоторыми дополнительными фишками…
И Hack офигенен! Я очень хочу, чтобы обозначенные мной проблемы HHVM каким-то образом решились, и я бы мог внести свой вклад!
Ведь это интересная идея. Сейчас существует несколько метаязыков, построенных на базе PHP. Лидеры — Hack и Zephir. Но есть проблема. Оба предназначены для конкретной среды исполнения: Hack работает на HHVM, а Zephir — на PHP. Как это разрешить?
Честно говоря, я бы просто выкинул Zephir и построил компилятор из Hack в PECL. Поскольку Hack — статически типизированный язык, должна быть возможность кросс-компиляции между Hack и PECL. А учитывая то, что Hack уже поддерживает привязки C++ (для подключения системных библиотек), теоретически компилятор должен обрабатывать и это. В таком случае уже бы не было смысла писать расширение PECL. Вы бы писали свое расширение на Hack (который располагает статическими анализаторами кода, дебаггерами), и генерировали бы стопроцентно совместимое расширение PECL. Эта вещь, конечно, весьма нетривиальна в реализации, но было бы здорово такое попробовать! Вот, кстати, и еще один аргумент в пользу спецификации языка.
О спецификации языка
Вы, наверное, заметили, что я уже несколько раз упомянул в тексте о необходимости спецификации языка…
Я намекаю на то, что это самая важная вещь, которая помогла бы улучшить будущее PHP как языка, платформы, экосистемы и сообщества.
Подытоживая
PHP вступает в очень интересную фазу своего развития. Люди пишут крутые штуки, двигают прогресс. Так что если мы хотим и дальнейшего роста PHP, думаю, мы должны о-очень хорошо понимать, что мы делаем, совершая тот или иной выбор.