- PVSM.RU - https://www.pvsm.ru -
Сегодня, наконец, опубликован релиз PHP 7.4 [1]!
Его новые фичи уже были многократно описаны [2], в том числе и на Хабре [3]. Это стрелочные функции, типизированные свойства классов и ещё много всякого синтаксического сахара. Но больше всего мы ждали новый релиз из-за производительности [4]: в версии 7.4 не только появился preload, но и сам PHP стал значительно быстрее.
Плохая (или хорошая?) новость — с выходом PHP 7.4 прекращается [5] активная поддержка PHP 7.2. Его последний релиз запланирован [6] на середину декабря. Мы давно проводим эксперименты с PHP 7.4, а недавно активно занялись переходом на него, так как сейчас мы на уже почти не поддерживаемой версии 7.2.
Поздравляю всех с долгожданным релизом! А ниже расскажу немного о том, как мы переходим на новую версию.
Несмотря на то, что у нас огромная кодовая база, мы живём на PHP уже 13 лет. Нам неоднократно приходилось переходить на новые версии, и процесс перехода хорошо отработан.
Если сильно упростить, то можно выделить несколько шагов:
В этот раз в процессе кое-что изменилось: так как мы очень ждали preload, начали проводить часть работы еще в июле, во время версии 7.4.0beta1. В итоге это вылилось для нас в достаточно большое количество времени, потраченного на отладку, ведь PHP 7.4 тогда был совсем сырым. Но с другой стороны, в результате мы нашли неприятный баг, починили его и отправили фикс в апстрим, чем помогли всему сообществу.
Дальше настало время заняться тестами.
Для того, чтобы вообще прогнать тесты, нужно обновить PHPUnit, SoftMocks и PHP-Parser как их часть. У нас большая кодовая база, и даже для обновления PHPUnit потребовалось переписать огромное количество тестов.
После того, как нам удалось прогнать тесты, мы увидели очень странное. Было много падений со следующей ошибкой:
PHP Fatal error: Cannot access private property ClassLoader::$classMap in vendor/composer/ClassLoader.php
Доступ к приватному свойству класса осуществляется только внутри него, но PHP рапортует об ошибке: нельзя получить доступ к приватному свойству, будто бы вызов происходит из другого класса.
Проблема осложнялась тем, что воспроизводилась нестабильно. Долгий дебаг при помощи gdb показал, что действительно в EG(fake_scope) [9] по каким-то причинам оказывается не тот класс, в рамках которого происходит обращение к свойству, а другой, не связанный с ним.
После того, как мы нашли минимальный репродьюс-кейс (который, на минуточку, требует наличия трёх классов, автолоадера и Reflection), починили причину проблемы и запушили [8] исправление в апстрим, оказалось, что эта проблема существовала ещё со времён PHP 7.3 (скорее всего, после вот этого [10] изменения), весь мир жил с ней год и никому до нас она не мешала.
Сейчас мы правим все несовместимости нашего кода с PHP 7.4. Подавляющее большинство несовместимостей для нас (больше сотни мест, >80% от всех несовместимостей) было вызвано добавлением ошибки «Trying to access array offset on value of type null/bool/int» (соответствующий RFC [11]). Она возникает при использовании синтаксиса обращения к элементу массива на других типах данных.
Проблему хорошо показывает вот такой пример:
$a = false;
var_dump($a[‘somekey’]);
// PHP 7.3:
// NULL
//
// PHP 7.4:
// Notice: Trying to access array offset on value of type bool in Command line code on line 1
// NULL
Навскидку кажется, что такого в реальном коде не должно встречаться, но, как показала практика, это достаточно частый случай: например, функция может возвращать массив в нормальном случае и false/null в случае ошибки, а дальше вверх по стеку информация о false/null теряется, и этот случай не обрабатывается отдельно.
Это достаточно слабо распиаренное, но полезное изменение в PHP: оно позволяет найти много потенциальных ошибок в коде.
Второе по количеству доставленных проблем обновление — это изменение [12] в работе method_exists(). Кстати, в настоящий момент информации о нём нет в release notes или upgrading guide. Суть его заключается в следующем:
class A1 {
private function priv() {}
}
class B1 extends A1 {}
var_dump(method_exists(B1::class, 'priv'));
// PHP 7.3: bool(true)
// PHP 7.4: bool(false)
Эту особенность, опять же, сложно встретить в реальном коде. Но, как оказалось, мы ненамеренно активно эксплуатировали это в тестах.
Конечно, мы в разной степени сталкиваемся и с другими несовместимостями, в том числе с многочисленными изменениями, связанными с рефлексией (пример один [13], пример два [14]), с изменениями [15] в hexdec() и подобных, запретом [16] array_key_exists() даже для ArrayAccess-объектов, с несовместимостями в различных бибилотеках зависимостей, подключаемых через Composer, и даже со всякими экзотическими штуками вроде ставшим обязательным [17] stream_set_option() для stream wrapper’ов при include’ах. Но в сумме затраты на адаптацию ко всем этим изменениям не сравнятся со случаем использования синтаксиса массивов на не-массивах.
В настоящий момент мы закончили работу с юнит-тестами: они полностью проходят на PHP 7.4. Ведём работу над API-тестами и до конца года планируем начать переключение различных кластеров и окружений.
Этой краткой заметкой хочу пригласить к обсуждению: пробовали ли вы уже PHP 7.4? Если да, то каким был ваш опыт? Собираетесь ли переходить?
Автор: Pavel Murzakov
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/338104
Ссылки в тексте:
[1] релиз PHP 7.4: https://www.php.net/archive/2019.php#2019-11-28-1
[2] описаны: https://www.php.net/manual/en/migration74.new-features.php
[3] на Хабре: https://habr.com/ru/company/funcorp/blog/454410/
[4] производительности: https://habr.com/ru/company/badoo/blog/472528/
[5] прекращается: https://www.php.net/supported-versions.php
[6] запланирован: https://externals.io/message/107849
[7] фикс: https://bugs.php.net/bug.php?id=78376
[8] фикс: https://bugs.php.net/bug.php?id=78868
[9] EG(fake_scope): https://github.com/php/php-src/blob/1a9a5f995c273b57ef1b42a8c68bcd736110b4a7/Zend/zend_globals.h#L163
[10] этого: https://github.com/php/php-src/commit/7ac06d66d4e19dc68b0440aff27f2a405354e5d6
[11] соответствующий RFC: https://wiki.php.net/rfc/notice-for-non-valid-array-container
[12] изменение: https://github.com/php/php-src/commit/6255308624a2a6bdbfa8581b9b920a8d180e458f#diff-f67c638590f0e9a686c5657200bcd82f
[13] пример один: https://github.com/php/php-src/commit/fc18f44213d59190a3e524e5c2f1a33f73be2cda
[14] пример два: https://github.com/php/php-src/commit/b964298c19c685f61542bbf30c49bd164b67c653
[15] изменениями: https://github.com/php/php-src/commit/d90cdbd9df42c3d012af23a64fb3062f0af60efa
[16] запретом: https://github.com/php/php-src/commit/0ba7c3eadf2683e4581079ea04b5b3019a5b6cce
[17] обязательным: https://github.com/php/php-src/commit/a986e70991057785cd3e5f4235215cb933351b4d
[18] Источник: https://habr.com/ru/post/477822/?utm_source=habrahabr&utm_medium=rss&utm_campaign=477822
Нажмите здесь для печати.