Содержание

оптимизация структур данных / Хабр

В декабре 2015 вышел PHP 7.0. Компании, которые перешли на «семерку» отметили, что увеличилась производительность, а нагрузка на сервера — уменьшилась. Первыми перешли на семерку Vebia и Etsy, а у нас Badoo, Авито и OLX. Для Badoo переход на семёрку обошелся в 1 млн. долларов экономии на серверах. Благодаря PHP 7 в OLX средняя нагрузка на сервер снизилась в 3 раза, повысилась эффективность и экономия ресурсов.

Дмитрий Стогов из Zend Technologies на HighLoad++ рассказал, благодаря чему повысилась производительность. В расшифровке: о внутреннем устройстве PHP, об идеях в основе версии 7.0, об изменениях в базовых структурах данных и алгоритмах, которые и определили успех.

Disclaimer: На март 2019 года 80% сайтов работают на PHP, и 70% из них — на PHP 5, хотя с 1 января 2019 эта версия не поддерживается. Доклад Дмитрия от 2016 года про принципы, благодаря которым произошел двукратный скачок производительности между PHP 5 и 7, — актуален и в марте 2019. Для половины сайтов — точно.

О спикере: Дмитрий Стогов начал программировать еще в 80-х: «Электроника Б3-34», Basic, ассемблер. В 2002 Дмитрий познакомился с PHP и вскоре, начал работать над его усовершенствованием: разработал Turck MMCache для PHP, руководил проектом PHPNG и играл важную роль в работе над JIT для PHP. Последние 14 лет Principal Engineer в Zend Technologies.

Zend Technologies занимается разработкой PHP и коммерческих решений на его основе. В 1999 её основали израильские программисты Энди Гутманс и Зеев Сураски, которые за два года до этого создали PHP 3. Эти люди стояли у истоков разработки PHP и во многом определили текущий вид языка и успех технологии.

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

Искать пути ускорения PHP я начал еще до прихода в Zend, работая над своим собственным проектом, который конкурировал с компанией. За время работы над проектом я досконально разобрался в языке и понял, что работая не с мейнстримным проектом, можно влиять только на отдельные аспекты исполнения скрипта, а все самое интересное и эффективное можно создать только в ядре. Это понимание и стечение обстоятельств привели меня в Zend.

Небольшой экскурс в историю PHP

PHP – это не совсем и не только язык программирования. PHP расшифровывается как Personal Home Page — инструмент создания персональных веб-страниц и динамических веб-сайтов. Язык – только одна из его основных частей. PHP — это огромная библиотека функций, множество расширений для работы с другими сторонними библиотеками, например, для доступа к БД или к парсерам XML, а также набор модулей для связи с различными веб-серверами.

Датский программист Расмус Лердорф представил PHP в июне 1995. На тот момент это был просто набор CGI-скриптов, написанных на Perl. В апреле 96 Расмус представил PHP/FI, а уже в июне вышла версия PHP/FI 2.0. Впоследствии эту версию существенно переработали Энди Гутманс и Зеев Сураски, и в 98-м выпустили PHP 3.0. К 2000 году язык пришел к тому виду, который мы привыкли видеть сегодня как с точки зрения языка, так и внутренней архитектуры — PHP 4, основанный на Zend Engine.

С 4-й версии PHP развивается эволюционно. Переломным моментом был выход PHP 5 в 2004, когда полностью обновилась объектная модель. Именно она открыла эру PHP фреймворков и поставила вопрос о производительности на новый уровень. Предвидя это, сразу после выхода 5.0 мы в Zend задумались об ускорении PHP и принялись работать над повышением производительности.

Версия 7.1, которая вышла в ноябре 2016 на синтетических тестах в 25 раз быстрее версии 2002 года. По графику изменения производительности в разных ветках, основные прорывы видны в 5.

1 и 7.0.

В версии 5.1 мы только запустили работу над производительностью, и все за что брались — получалось, но после 5.3 — уперлись в стену, все попытки усовершенствовать интерпретатор ни к чему не приводили.

Тем не менее мы нашли, куда копать, и получили даже больше, чем ожидали, — 2,5-кратное ускорение по сравнению с предыдущей версией 5.6 на тестах. Но самое интересное, что то же 2,5-кратное ускорение мы получили и на неизменных реальных приложениях. Это феномен, потому что предыдущий фактор 2 мы нарабатывали в течении всей жизни пятерки за 10 лет.

Огромный скачок в 5.1 на синтетических тестах, на реальных приложениях не заметен. Причина в том, что при разных использованиях производительность PHP упирается в тормоза, связанные с разными подсистемами.

История PHP 7 начинается с трехлетнего застоя, который начался в 2012, а закончился в 2015 с релизом седьмой версии. Тогда мы поняли, что не можем больше увеличивать производительность мелкими усовершенствованиями нашего интерпретатора и обратились в сторону JIT.

Блуждание около JIT

Почти два года мы потратили на прототип JIT для PHP-5.5. Сначала мы генерировали очень простой код – последовательность вызовов для стандартных обработчиков, что-то наподобие сшитого кода Форта. Затем написали собственный

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

Тогда мы задумались о выводе типов переменных, используя методы статического анализа. Реализовав вывод, сразу же получили 2-кратное ускорение на тестах. Воодушевленные, попытались написать глобальные register allocator, но потерпели неудачу. Мы использовали достаточно высокоуровневое представление, а для распределения регистров применять его было практически невозможно.

Чтобы избежать проблем с низким уровнем, решили попробовать LLVM, и через год у нас получилось 10-кратное ускорение для bench. php, а на реальных приложениях — ничего. Кроме того, компиляция реальных приложений теперь занимала минуты, например, первый реквест к WordPress занимал 2 минуты и не давал ускорения. Конечно, это совершенно не подходило для реальной практики.

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

Что же тормозит?

Мы переосмыслили причины неудач и решили еще раз посмотреть, почему тормозит PHP. На картинке результат профилирования нескольких запросов к домашней странице WordPress.

На интерпретацию байт-кода тратится меньше 30%, 20% — это накладные расходы memory-менеджера, 13% — это работа с хэш-таблицами, и 5% — работа с регулярными выражениями.

Работая на JIT, мы избавлялись только от первых 30%, а все остальное лежало мертвым грузом. Практически везде мы были вынуждены использовать стандартные структуры данных PHP, которые влекли за собой накладные расходы: распределение памяти, подсчет ссылок, и т.

п. Это понимание и привело к выводу о необходимости замены ключевых структур данных в PHP. С этой подмены фундамента и начался проект PHPNG.

PHPNG. New Generation

Проект получил развитие после безрезультатных попыток создать JIT для PHP. Основная цель — достичь нового уровня производительности и заложить базу для будущих улучшений.

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

Проект PHPNG — это рефакторинг ключевых структур данных PHP для оптимизации обращения к памяти. Никаких нововведений, 100% совместимость с PHP 5.

Как менять эти структуры было понятно. Но объем зависимых изменений был огромен, потому что само ядро PHP – это 150 000 строк, и почти каждая третья нуждалась в изменении. Прибавьте ещё сотню расширений, которые входят в base distribution, десяток модулей для разных веб-серверов, и вы поймете грандиозность проекта.

Мы даже не были уверены, что доведем проект до конца. Поэтому запустили проект в тайне и открыли его, только когда появились первые оптимистичные результаты. Две недели ушло на то, чтобы просто скомпилировать ядро. Еще через две недели заработал bench.php. Полтора месяца потратили для обеспечения работы WordPress. Еще через месяц мы открыли проект — это был май 2014 года. На тот момент у нас было ускорение на 30% на WordPress. Это уже казалось грандиозным событием.

PHPNG сразу вызвал волну интереса, и в августе 2014

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

PHP 7.0

Сам номер версии 7 был под вопросом. Предыдущая версия была пятая. А шестая разрабатывалась несколько лет назад и была полностью посвящена нативной поддержке Unicode, но неудачные решения, принятые на ранних этапах разработки, привели к чрезмерному усложнению кода ядра и каждого расширения. В конце концов было принято решение о заморозке проекта.

К этому времени уже было накоплено много материала, посвящённого PHP 6: выступления на конференциях, опубликованные книги. Чтобы никого не путать, мы назвали проект PHP 7, пропустив PHP 6. Этой версии повезло куда больше — PHP 7 вышел в декабре 2015, почти по плану.

Кроме производительности, в PHP 7 появились некоторые давно востребованные нововведения:

  • Возможность определять скалярные типы параметров и возвращаемых значений.
  • Исключения вместо ошибок — теперь мы можем их ловить и обрабатывать.
  • Появились Zero-cost assert(), анонимные классы, чистка неконсистентностей, новые операторы и функции (<=>, ??).

Нововведения это хорошо, но вернемся ко внутренним изменениям. Поговорим о пути, который прошел PHP 7, и о том, куда этот путь нас может завести.

zval

Это основная структура данных PHP. Она используется для представления любого значения в PHP. Так как язык у нас динамически типизированный и тип переменных может меняться во время выполнения программы, нам необходимо хранить поле типа (zend_uchar type), которое может принимать значения IS_NULL, IS_BOOL, IS_LONG, IS_DOUBLE, IS_ARRAY, IS_OBJECT и т.д., и собственно значение, представленное union-ом (value), где может храниться целое, вещественное число, строка, массив или объект.

zval в PHP 5

Память под каждую такую структуру выделялась отдельно в Heap. Помимо типа и значения в ней же хранился счетчик ссылок на структуру. Так структура занимала 24 байта, не считая накладные расходы memory-менеджера и указателя на нее.

На картинке справа сверху показаны структуры данных, которые создавались в памяти PHP 5 для простого скрипта.

На стеке выделилась память под 4 переменные, представленные указателями. Сами же значения (zval) лежат в куче. В нашем случае это всего два zval, на каждый из которых ссылаются две переменные, и соответственно их счетчики ссылок установлены равными 2.

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

zval в PHP 7

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

Слева — как это выглядело в PHP 5, а справа — в PHP 7.

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

Копирование записи

В верхней строчке скрипта добавилось еще одно присваивание.

В PHP5 мы выделяли из кучи память под новый zval, инициализировали его int(2), изменяли значение указателя переменной b и уменьшали reference counter того значения, на которое b ссылалось раньше.

В PHP 7 мы просто инициализировали переменную b прямо по месту с помощью нескольких инструкций, в то время как в PHP 5 это требовало сотен инструкций. Так zval выглядит сейчас в памяти.

Это два 64-битных слова. Первое слово — значение: целое число, вещественное или указатель. Во втором слове тип (он говорит, как интерпретировать значение), флаги, и зарезервированное место, которое все равно добавилось бы при выравнивании. Но оно не пропадает, а используется разными подсистемами для хранения косвенно связанных значений.

Флаги — это набор битов, где каждый бит говорит о том, поддерживает ли zval какой-то протокол. Например, если стоит IS_TYPE_REFCOUNTED, то при работе с данным zval, engine должен заботиться о значении счетчика ссылок. При присваивании — увеличивать, при выходе из области видимости — уменьшать, если reference counter достиг нуля — уничтожать зависимую структуру.

Из типов, по сравнению с PHP 5, появилось несколько новых.

  • IS_UNDEF — маркер неинициализированной переменной.
  • На смену единому IS_BOOL пришли раздельные IS_FALSE и IS_TRUE.
  • Добавился отдельный тип для ссылок и еще несколько магических типов.

Типы от IS_UNDEF до IS_DOUBLE — скалярные, и не требуют дополнительной памяти. Для их копирования достаточно скопировать первое машинное 64-битное слово со значением и половину второго с типом и флагами.

Refcounted

С другими типами сложнее. Все они представлены подчиненной структурой, и в zval хранится просто ссылка на эту структуру. Для каждого из типов эта структура своя, но в терминах ООП все они имеют общего абстрактного предка или структуру zend_refcounted. Она определяет формат первого 64-битного слова, где хранится счетчик ссылок и другая информация для сборщика мусора.

Это слово можно рассматривать просто как информацию для сборщика мусора, а структуры для конкретных типов добавляют свои поля вслед за этим первым словом.

Строки

В семёрке для строки мы храним вычисленное значение хэш-функции, её длину и сами символы. Размер такой структуры переменный и зависит от длины строки. Хэш-функция вычисляется для строки один раз, при первой необходимости. В PHP 5 она заново вычислялась при каждой потребности.

Теперь строки стали reference countable, и если в PHP 5 мы копировали сами символы, то теперь достаточно увеличить счетчик ссылок на данную структуру.

Так же как и в PHP 5 у нас осталось понятие неизменяемых или interned-строк. Они обычно существуют в одном экземпляре, живут до конца запроса и могут вести себя как скалярные значения. Нам незачем заботиться о счетчике ссылок на них, и для копирования достаточно скопировать только сам zval с помощью четырех машинных инструкций.

Массивы

Массивы представлены встроенной хэш-таблицей и мало чем отличаются от PHP 5. Сама хэш-таблица изменилась, но об этом отдельно.

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

Так хэш-таблица выглядит в PHP 5.

Это классическая реализация хэш-таблицы с разрешением коллизий с помощью линейных списков (показана в правом верхнем углу). Каждый элемент представлен Bucket. Все Buckets связаны двусвязными списками для разрешения коллизий, и связаны еще другим двусвязным списком для итерации по порядку. Значения под каждый zval выделяются отдельно — в Bucket мы храним только ссылку на него. Также строковые ключи могут выделяться отдельно.

Таким образом, под каждую хэш-таблицу нужно выделять очень много мелких блоков памяти, а чтобы потом что-то найти, приходится бегать по указателям. Каждый такой переход может вызвать cahce miss и задержку на ~10-100 циклов процессора.

Вот что получилось в PHP 7.

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

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

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

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

Неизменяемые массивы

Раньше у нас были неизменяемые строки, а теперь появились еще и неизменяемые массивы. Как и строки они не используют счетчик ссылок и не уничтожаются до конца запроса. Это простой скрипт, который создает массив из миллиона элементов, а каждый элемент — это один и тот же массив с единственным элементом «hello».

В PHP 5 на каждой итерации цикла создавался новый пустой массив, в него записывалось «hello», и все это добавлялось в результирующий массив. В PHP 7 на этапе компиляции мы создаем всего один неизменяемый массив, который ведет себя как скаляр, и добавляем его в результирующий. На представленном примере это позволяет добиться более чем 10-кратного уменьшения потребления памяти и почти 10-кратного ускорения.

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

Объекты

Ссылки на все объекты в PHP 5 лежали в отдельном хранилище, а в zval был только handle — уникальному ID объекта.

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

В PHP 7 мы смогли перейти к прямой адресации.

Теперь адрес zend_object доступен с помощью одной машинной инструкции. А Property встроены и для их чтения нужно всего одно дополнительное чтение. Также они сгруппированы вместе, что улучшает data locality и помогает современным процессорам не спотыкаться.

Кроме предопределенных property здесь же хранится ссылка на класс данного объекта, некие handlers — аналог таблиц виртуальных методов, и хэш-таблица для property, которые не были определены. В PHP к любому объекту можно добавить property, которые изначально не были определены, и если для доступа к предопределенным property достаточно нескольких машинных инструкций, то для не предопределенных придется обращаться к хэш-таблице, что потребует десятков машинных инструкций. Конечно, это намного дороже.

Reference

Наконец, нам пришлось ввести отдельный тип для представления PHP ссылок.

Это абсолютно прозрачный тип. Он не виден PHP скриптам. Скрипты видят другой zval, который встроен в структуру zend_reference. Подразумевается, что на одну такую структуру у нас ссылаются как минимум из двух мест, и reference counter этой структуры всегда больше 1. Как только счетчик падает до 1, ссылка превращается в обычное скалярное значение. Встроенный в ссылку zval копируется в последний ссылающийся на него zval, а сама структура удаляется.

Кажется, что теперь работа с reference намного сложнее, чем с другими типами (и это действительно так), но на самом деле в PHP 5 нам приходилось выполнять сопоставимую по сложности работу при обращении к любому значению (даже простому целому числу). Теперь же мы применяем более сложные протоколы только к одному типу и тем самым ускорили работу со всеми другими, особенно со скалярными значениями.

IS_FALSE и IS_TRUE

Я уже говорил, что единый тип IS_BOOL был разбит на отдельные IS_FALSE и IS_TRUE. Эта идея была подсмотрена в реализации LuaJIT, а сделана для ускорения одной из наиболее частых операций — условного перехода.

Если в PHP 5 требовалось прочитать тип, проверить на boolean, прочитать значение, узнать true оно или false и сделать переход на основании этого, то теперь достаточно просто проверить тип и сравнить его с true:

  • если он равен true, то идем по одной ветке;
  • если он меньше true, идем по другой ветке;
  • если он больше true, идем на так называемый slow path (медленный путь) и там проверяем, что это за тип пришел и что с ним делать: если это integer, то мы должны сравнить его значение с 0, если float — опять с 0 (но вещественным), и т.д.

Calling Convention

Изменение в Calling Convention или соглашении о вызовах функций — важная оптимизация, которая затрагивает не только структуры данных, но и базовые алгоритмы. На картинке слева небольшой скрипт, состоящий из функции foo() и ее вызова. Ниже — байт-код, в который этот скрипт был скомпилирован PHP 5.

Сначала расскажу, как это работало в PHP 5.

Calling Convention в PHP 5

Первая инструкция SEND_VAL должна была отправить значение «3» в функцию foo. Для этого она была вынуждена аллоцировать новый zval на куче, копировать туда значение (3) и записать на стек значение указателя на эту структуру.

Аналогично со второй инструкцией. Дальше DO_FCALL инициализировал CALL FRAME, резервировал место под локальные и временные переменные, и передавал управление на вызываемую функцию.

Первый оператор RECV проверял первый аргумент и инициализировал на стеке слот соответствующей локальной переменной ($a). Тут мы обошлись без копирования и просто увеличили счетчик ссылок соответствующего параметра (zval со значением 3). Аналогично второй оператор RECV устанавливал связь между переменной $b и параметром 5.

Дальше тело функции. Произошло сложение 3 + 5 — получилось 8. Это временная переменная и ее значение хранилось непосредственно на стеке.

RETURN и мы возвращаемся из функции.

При возврате освобождаем все переменные и аргументы, которые вышли из области видимости. Для этого проходим по всем zval на которые ссылаются слоты из освобождаемого фрейма, и для каждого уменьшаем счетчик ссылок. Если он достиг 0, то уничтожаем соответствующую структуру.

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

Calling Convention в PHP 7

В PHP 7 эти проблемы исправили — теперь на стеке храним не указатели на zval-ы, а сами zval-ы.

Также мы ввели новую инструкцию INIT_FCALL, которая теперь отвечает за инициализацию и выделение памяти под CALL FRAME, и резервацию места под аргументы и временные переменные.

SEND_VAL 3 теперь просто копирует аргумент в первый слот за CALL FRAME. Следующий SEND_VAL 5 во второй слот.

Дальше самое интересное. Казалось бы, DO_FCALL должна передать управление на первую инструкцию вызываемой функции. Но аргументы уже попали в слоты, которые зарезервированы для переменных параметров $a и $b, и инструкциям RECV просто ничего делать. Поэтому можно их просто пропустить. Мы посылали два параметра, поэтому пропускаем две инструкции. Если бы посылали три — пропустили бы три.

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

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

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

Новый Calling Convention немного сломал совместимость. В PHP есть такие функции, как func_get_arg и func_get_args. Если раньше они возвращали оригинальное значение посланного параметра, то теперь возвращают текущее значение соответствующей локальной переменной, потому что мы просто не храним оригинальные значения. Так же как делают отладчики C.

Кроме того, функция теперь не может иметь несколько параметров с одинаковым именем. Смысла в этом не было и раньше, но такой PHP код foo($_, $_) я встречал. На что это похоже? (Я узнал Prolog)

Новый менеджер памяти

Закончив с оптимизацией структур данных и базовых алгоритмов, мы еще раз обратили внимание на все тормозящие подсистемы. Менеджер памяти в PHP 5 занимал почти 20% процессорного времени на WordPress.

После того, как мы избавились от множества аллокаций, его накладные расходы стали меньше, но все равно существенны — и не потому что он делал какую-то существенную работу, а потому, что спотыкался на кэше. Происходило это из-за того, что мы использовали классический алгоритм Doug Lea’s malloc, который подразумевал поиск подходящих свободных участков памяти с помощью путешествия по ссылкам и деревьям, а все эти путешествия неминуемо вызывали промахи кэша.

Сегодня существуют новые алгоритмы управления памятью, которые учитывают особенности современных процессоров. Например: jemalloc и ptmalloc от Google. Сначала, мы попытались использовать их в неизменном виде, но не получили выигрыша, поскольку отсутствие специфичного для PHP функционала удорожало полное освобождение памяти в конце реквеста. В итоге мы отказались от dlmalloc и написали что-то свое, скомбинировав идеи из старого memory manager и jemalloc.

Мы сократили накладные расходы Memory Manager до 5%, уменьшили издержки памяти на служебную информацию и улучшили использование кэша CPU. Подходящие блоки памяти теперь ищутся по битовым картам, память под блоки небольшого размера выделяется из отдельных страниц и кэшируется при освобождении, добавлены специализированные функции для часто используемых размеров блоков.

Множество мелких усовершенствований

Я рассказал только о самых главных усовершенствованиях, но мелких было куда больше. Могу отметить некоторые из них.

  • Быстрый API для разбора параметров внутренних функций и новый API для итерации по HashTable.
  • Новые инструкции VM: конкатенация строк, специализация, супер-инструкции.
  • Некоторые внутренние функции были превращены в инструкции VM: strlen, is_int.
  • Использование регистров CPU под регистры VM: IP и FP.
  • Оптимизация функций дублирования и удаления массивов.
  • Использование счетчиков ссылок вместо копирования везде, где можно.
  • PCRE JIT.
  • Оптимизация внутренних функций и serialize().
  • Уменьшение размера кода и обрабатываемых данных.

Одни были очень простыми, например, потребовалось всего три строчки кода, чтобы включить JIT в регулярных перловских выражениях, и это сразу принесло видимое (2-3%) ускорение почти всем приложениям. Другие оптимизации затрагивали какие-то узкие аспекты определенных PHP функций, и не особо интересны, хотя суммарный вклад всех этих мелких усовершенствований вполне значим.

К чему пришли

Это вклад различных подсистем на WordPress/PHP 7.0.

Вклад виртуальной машины увеличен до 50%. Memory Manager потребляет уже меньше 5% — и в основном не за счет оптимизаций самого Memory Manager, а за счет уменьшения количества обращений к нему. Если раньше на этом же тесте память выделялась 130 млн. раз, то сейчас только 10 млн. Может показаться, что все основное ускорение достигнуто за счет уменьшения накладных расходов Memory Manager и уменьшения количества обращений к нему за счет улучшения структур данных, но на самом деле все подсистемы были существенно усовершенствованы.


Основные источники ускорения:

  • Интерпретатор стал работать лучше в 2 раза.
  • Накладные расходы MM уменьшились в 17 раз.
  • Хэш-таблицы стали работать быстрее в 4 раза.
  • Общая производительность на WordPress выросла в 3,5 раза.

В начале статьи мы говорили о 2,5-кратном реальном ускорении, а сейчас цифры другие. Почему так? Дело в том, что реальную скорость мы измеряли в запросах в секунду, а здесь скорость измерена профилировщиком в терминах CPU time, по сути — тактах процессора, когда он не простаивает. Когда PHP ждет ответа от базы данных, процессор стоит и это время здесь не учитывается.

Производительность PHP 7

WordPress 3.6 был для нас основным бенчмарком — на нём мы мониторили производительность с первых дней работы. В какой-то момент, когда из PHP 7 выкинули расширение mysql, нам пришлось его специально поддерживать, просто чтобы продолжить этот график.

На графике видно, что основные прорывы произошли в первые месяцы работы над PHPNG. К августу было набрано 2/3 улучшений. Дальше мы двигались маленькими шажками, и набрали оставшуюся треть.

Разумеется, мы измеряли производительность не только на WordPress, но и на других популярных приложениях, и практически везде мы видим — от 1,5 до 2-кратное ускорение.

PHP 7 и HHVM

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

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

Апофеоз PHP 7 — начало использования крупными сайтами. Пионерами были китайский Vebia, американский Etsy и Badoo. Highload-проверка вскрыла несколько существенных проблем, но они были быстро локализованы и пофикшены.

Переход на PHP 7.0 для Etsy и Badoo позволил выключить практически половину серверов в веб-фермах. Badoo оценил экономию в миллион долларов.

Показательны графики, что на момент перехода суммарная загрузка процессоров уменьшилась в 2 раза, а потребление памяти — аж в 7 раз.

На этой радостной ноте закончим сегодняшний разговор о PHP 7.0. Но продолжим его в второй части, посвященной PHP 7.1, в оптимизации которого пошли существенно дальше структур данных.

В мае на PHP Russia Дмитрий Стогов выступит с докладом о самых интересных новых технологиях разрабатываемых для PHP 8. Если и ваш опыт во многом связан с PHP, вы знаете, как его правильно готовить, и готовы поделиться своими наработками — присылайте заявки до 1 апреля. И помните, главное, что мы ищем — живой полезный опыт, а с докладом поможем, зададим правильные вопросы и подскажем, куда двигаться.

Что нового в PHP 8, сравнение с PHP 7

PHP 8 стал еще более быстрым и надежным. По сравнению с версией PHP 7 появилось множество новых и полезных вещей, которые обязательно будут востребованы пользователями. Рассмотрим подробнее эти нововведения.

Типы Union 2.0 (Объединенные типы)

Существует множество случаев, когда использование типов объединения может быть полезным. Вместо аннотаций PHPDoc для объединенных типов теперь вы можете использовать объявления union type, которые проверяются сразу во время выполнения.

Union Types — это совокупность двух или более типов, которые указывают, что вы можете использовать любой из них.

JIT – компилятор

JIT (Just In Time — «в нужный момент») — это динамическая компиляция байт кода в машинный. JIT компилятор значительно улучшает производительность работы программ. Проверка на синтетических бенчмарках показывает улучшение производительности примерно в 3 раза и в 1,5–2 раза для некоторых долго работающих приложений. 

В JIT код переводится сначала в промежуточное представление и только потом в машинный код. То есть, выполняется непосредственно на процессоре, а не на виртуальной машине Zend VM.

JIT реализован как независимая часть OPcache. Его можно включать / отключать во время компиляции или выполнения скрипта.

Использование ::class для объектов

В PHP 8 теперь вы можете использовать ::class для объектов вместо того, чтобы использовать get_class() как раньше. Работает точно так же, как и get_class().

Атрибуты

В PHP 8 теперь вместо аннотаций PHPDoc вы можете использовать структурные метаданные с нативным синтаксисом PHP.

Выражение Match

В PHP 8 новое выражение match похоже на оператор switch, но имеет свои особенности:

  • Match — это выражение и его результат может быть сохранён в переменной или возвращён.
  • Условия match поддерживают только однострочные выражения, для которых не требуется управляющая конструкция break;
  • Выражение match использует строгое сравнение.
Оператор Nullsafe

В PHP 8 теперь вместо проверки на null вы можете использовать последовательность вызовов с новым оператором Nullsafe. Если один из элементов в последовательности возвращает null, то выполнение прерывается и вся последовательность возвращает null.

Улучшенное сравнение строк и чисел

Теперь при сравнении с числовой строкой PHP 8 использует сравнение чисел. В противном случае число преобразуется в строку и используется сравнение строк.

Ошибки согласованности типов для встроенных функций

В PHP 8 большинство внутренних функций теперь выбрасывают исключение Error, если при проверке параметра возникает ошибка.

Именованные аргументы

В PHP 8 теперь можно:

  • Указывать только необходимые параметры и пропускать необязательные.
  • Порядок аргументов не важен, аргументы самодокументируемы.
Объявление свойств в конструкторе

В новой версии PHP 8 теперь используется гораздо меньше шаблонного кода для определения и инициализации свойств.

Новый тип возврата static

Ранее в PHP уже были возвращаемые типы — self и parent, но static не был допустимым типом возврата для этого языка программирования. Теперь есть.

Throw-выражения

В PHP оператор throw не может создавать исключения там, где были разрешены только выражения, например стрелочные функции, оператор объединения и тернарный оператор.

В новом PHP 8 теперь вы можете преобразовывать инструкцию throw в выражение.

Weak maps

Weak maps — это набор объектов, на которые в коде слабо ссылаются ключи, что может привести к их удалению сборщиками мусора. В PHP 8 добавлен класс WeakMaps для создания сохранения ссылки на объект. При этом она не препятствует удалению самого объекта.

Завершающая запятая в списках параметров

Ранее при вызове функции в списках параметров отсутствовала поддержка запятой. В PHP 8 теперь это разрешено.

Новый Stringable интерфейс

В PHP 8 теперь вы можете использовать интерфейс Stringable для аннотации типов или имплементации метода __toString (). И больше нет необходимости реализовывать его вручную.

Новые функции в PHP 8
  1. get_debug_type() — возвращает тип переменной. В отличии от gettype() возвращает более полезный вывод для массивов, строк, анонимных классов и объектов.
  1. str_starts_with() — проверяет, начинается ли строка с определенной строки. Возвращает TRUE / FALSE.
  1. str_ends_with() — проверяет, заканчивается ли строка с определенной строки. Возвращает TRUE / FALSE.
  1. str_contains() — проверяет, содержит ли строка другую строку.
  1. fdiv() — эта функция похожа на fmod() и intdiv(), что позволяет делить на 0. Но вместо ошибок получаем INF, -INF или NAN, в зависимости от случая.

6. get_resource_id() — ранее ресурсам присваивается идентификатор, но для этого необходимо было преобразование ресурса в int. В PHP 8 добавлена функция get_resource_id(), что делает эту операцию более очевидной и безопасной для типов.

К сожалению многие CMS пока не поддерживают PHP 8, в частности и 1С-Битрикс. В любом случае поддержка PHP 8 скоро появится на всех тарифах нашего хостинга.

Подробнее ознакомиться с нововведениями можно на официальной странице проекта.

 

php7

  • Популярные
  • Последние
  • Без ответа
  • +11Купить в 1 клик и php 7.1 Исправлено

    При любом обновлении движка у меня слетает плагин купить в один клик, а именно плагин не дает редактировать заказ, при установленном php 7. 1 , как то можно решить эту проблему? Разработчик плагина пишет, что это проблема движка и разработчики движка не…

  • Shop-Script переход на PHP7 Есть решение

    Добрый день, перевел хостинг с PHP5. 2 на PHP7, расширение mysqli включено. Но после этого выдает ошибку — Fatal error: Uncaught Error: Call to undefined function mysql_connect() in…

  • +1PHP 7 — перестали работать обновления. Не принято

    Добрый день!На сайте поменялась версия PHP. Теперь я почти довольный обладатель PHP7. Кстати, прирост скорости ответа сервера более чем в 2 раза.Но перестали работать обновления. При попытке обновить SS или установить плагин вылетает ошибка 500.Fatal…

  • Переход на php 7 ? Есть решение

    Меняю на сервере версию php на седьмую, админка и сайт перестают работать. Ошибка базы данных.Максимально идёт на php 5.6Может какие-нибудь действия ещё нужно предпринять? Спасибо.

  • Shop-Script будет работать на PHP 7?

    Вышел PHP 7. Webasyst shop-script и плагины к нему будут поддерживать PHP 7 или нужна адаптация для корректной работы?

  • org/Article»>

    0Ошибка при установке

    При установке фреймворка Webasyst на конфигурации Apache 2.4.18 + PHP 7.0.4-7 в лог апача пишутся ошибки:[data-time] [:error] [pid] [client] PHP Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP;…

PHP для Windows: бинарные файлы и исходники Релизы

    • Дом
    • загрузок
    • QA Релизы
    • Снимки
    • Команда
    • Сайт PHP. net
    • Выберите параметр для прямого доступа… VS16 x64 Non Thread SafeVS16 x64 Thread SafeVS16 x86 Non Thread SafeVS16 x86 Thread SafeVS16 x64 Non Thread SafeVS16 x64 Thread SafeVS16 x86 Non Thread SafeVS16 x86 Thread SafeVC15 x64 Non Thread SafeVC15 x64 Thread SafeVC15 x86 Non Thread SafeVC15 x86 Thread Safe

      Прошлые выпуски

      PHP 8.2

      8.2 не имеет релиза.

      PHP 8.1 (8.1.11)

      Загрузить исходный код [25,36 МБ]

      Загрузить пакет тестов (phpt) [15,13 МБ]

      VS16 x64 Non Thread Safe (2022-Sep-28 11:38:56)
      • Почтовый индекс [29.25МБ]
        sha256: a3904d05700b56186ab9c7f5e472bad9a40ad60cd8ef8fd68be6d55a4a756296
      • Пакет отладки [23,84 МБ]
        sha256: cf2074ccef2ceffaf34940c44610093c499baffaba8e78b36e1d79d97b467b18
      • Пакет разработки (SDK для разработки расширений PHP) [1,21 МБ]
        sha256: e92f740408a3a5d
      • f4352b05106ee93edfea0d49b59ca8b68342189124f4
      1-ts-vs16-x64″> VS16 x64 Thread Safe (2022-Sep-28 11:42:16)
      • Почтовый индекс [29.35МБ]
        sha256: 516cbb223a54b00f3b020fd3c6767e8ac12a7edb773323d3bf0469583027183f
      • Пакет отладки [23,84 МБ]
        sha256: ee7b75e3a6d8a78c0f8d05d6036b5ae41cf831630e2fedf895d191ce9991253d
      • Пакет разработки (SDK для разработки расширений PHP) [1,21 МБ]
        sha256: 7930e8e8d37017995ffc3c6fc980bb1555736274643c47cf52bc4c0da2e95c29
      VS16 x86 Non Thread Safe (2022-Sep-28 11:39:16)
      • Почтовый индекс [26,31 МБ]
        sha256: 45d2ba8bee148f1eb6d0454def4ed0fb71f4fc694776465406eca2701babd5a2
      • Пакет отладки [24.39МБ]
        sha256: f4ae8f70c18265c3505f1dee058fceccb9b4f04f5d8f605deaf335ea5b2da7a7
      • Пакет разработки (SDK для разработки расширений PHP) [1,21 МБ]
        sha256: e24bdb152ce8d6da6c2ea4bdbabfae525051c386a419468821f1c795f4afe6f1
      VS16 x86 Thread Safe (2022-Sep-28 11:46:36)
      • Почтовый индекс [26. 29МБ]
        sha256: 1b6be0d07486835a620ff67842ef130396872b92b577f7a540e312b599781285
      • Пакет отладки [24,05 МБ]
        sha256: 6402cb0e7ae37aec4ae2bfb523231f45dffc7b499bdc8f34fadf75de908ee897
      • Пакет разработки (SDK для разработки расширений PHP) [1,21 МБ]
        ша256: 0204c81845b73984e66ab4c72e8a4051e9e9f10782fbf8dd62d764381a27c659

      PHP 8.0 (8.0.24)

      Загрузить исходный код [23,45 МБ]

      Загрузить пакет тестов (phpt) [13,54 МБ]

      VS16 x64, не потокобезопасный (2022-Sep-28 18:07:20)
      • Почтовый индекс [25,52 МБ]
        sha256: e060d704a0d3de01c1bd1d98e5440ca89c02315fc39372d079d831002fff36e3
      • Пакет отладки [23,21 МБ]
        sha256: e1dd6d3fdfe87a5819c9fddbbf9d598fbd9c7af6727acf1c3ec391ddd1471c37
      • Пакет разработки (SDK для разработки расширений PHP) [1,16 МБ]
        sha256: e494b36c972f1cfb42b3199769f708c868062e79690f609e62ab29e19ec0660e
      0-ts-vs16-x64″> VS16 x64 Thread Safe (28 сентября 2022 г., 18:12:28)
      • Почтовый индекс [25,63 МБ]
        sha256: 976a825ca08c16700e7fee380fef36b7342b04615d39dd5f6a8f3e671d82c7ce
      • Пакет отладки [23,21 МБ]
        sha256: 6b00e2e7bc1de920e2fca75fb837d253
      96598f4eb5d228714
    • 7d4e0
    • Пакет разработки (SDK для разработки расширений PHP) [1,16 МБ]
      sha256: e63dc2c0a381f572551bb55ed7817a4e32ab4c2b2018bc0522edd8a2dcbbc9e9
    VS16 x86 Non Thread Safe (2022-Sep-28 18:18:08)
    • Почтовый индекс [23,65 МБ]
      sha256: bdfba738b77409946f10905d579ea9a9d8018df9e36df80334e9f169aebb50a8
    • Пакет отладки [23,86 МБ]
      sha256: b5f42863aedf1a222b58e0f94c278851db521bb5e20892360e90d67295ef03a9
    • Пакет разработки (SDK для разработки расширений PHP) [1,16 МБ]
      sha256: fd02baa4ef7cc75515ba1c7327173084546dab74647e3b0db9e1aa9f885f2d6d
    VS16 x86 Thread Safe (28 сентября 2022 г.
    , 18:07:08)
    • Почтовый индекс [23,64 МБ]
      sha256: 5e93a2b54d8bf9ace177ae4b0c0349c462c19c80bebd59e24ecb71d27e7a5f72
    • Пакет отладки [23,52 МБ]
      sha256: f31a2edf2cb8571124f60e417b7bcde799748959a779d1844903ab7b832ea989
    • Пакет разработки (SDK для разработки расширений PHP) [1,16 МБ]
      sha256: 96897f9d6f1958021a8e0f03e2defe35c628cf715b3f7b85e39af10c4d5c208f

    PHP 7.4 (7.4.32)

    Загрузить исходный код [22,85 МБ]

    Загрузить пакет тестов (phpt) [13,54 МБ]

    VC15 x64 Non Thread Safe (2022-Sep-29 18:49:56)
    • Почтовый индекс [24,92 МБ]
      sha256: cee0505fd40cb86fcd01d2504f6face37a199c7078ade66997c933fe3cfe887f
    • Пакет отладки [22 МБ]
      sha256: f84a2fd00e1e4e4427b3d3e638c77a312e29c9589d96fbe59dc39eca6e885d9d
    • Пакет разработки (SDK для разработки расширений PHP) [1,08 МБ]
      sha256: ba60dfaa50221cdf73c4d236aa2c2794a3c98dbda82b4e82efdcfba2fb07ec91
    4-ts-vc15-x64″> VC15 x64 Thread Safe (2022-Sep-29 18:50:13)
    • Почтовый индекс [25.02МБ]
      sha256: 2f302d3c1252cf617397f3c8b405729d2049c19870a2b83c4ff12bafa65ebf26
    • Пакет отладки [22МБ]
      sha256: a2cbf7ac6a50339fc5ce0807e4a7526157f9954a7a8ee4d46c31ce20f59296ff
    • Пакет разработки (SDK для разработки расширений PHP) [1,08 МБ]
      sha256: 2f2e9f6da0f952fcc2d5ce358446b2f8dbd677ef77b9f5e912d55fbf28a2b14b
    VC15 x86 Non Thread Safe (2022-Sep-29 18:49:56)
    • Почтовый индекс [23,2 МБ]
      sha256: fa54bbb23a4e09683e9325b479d012d1a221edc3d41708daff54356e8d892f6f
    • Пакет отладки [22,91 МБ]
      sha256: cf01fa199b3bddf18a6fc24bd0c7322ad0fe66735fdf33981adafca7d82341a2
    • Пакет разработки (SDK для разработки расширений PHP) [1,08 МБ]
      sha256: 62119bf252eee2dc3c904fbd5352089484a2d1d2c06e965de1a18074f71f48d3
    VC15 x86 Thread Safe (2022-сен-29 18:50:29)
    • Почтовый индекс [23,17 МБ]
      ша256: 07a63257df95d31fcd122a8da561478760e0317d29c791d945b0fb94b7f26478
    • Пакет отладки [22,58 МБ]
      sha256: 356a1040bbd51bb971fcaa1be0c5679ee8ff10b11f1c76ddd70222bd086e20af
    • Пакет разработки (SDK для разработки расширений PHP) [1,08 МБ]
      sha256: d9dca83c30c61c140f4030ebce4e96f9052454f633dbb562a8eb6f7ccd3ba5bb

PHP: Ключи GPG

Начиная с апреля 2012 года теги выпуска PHP были подписаны в Git менеджеры релизов для каждой ветки. Следующие ключи GnuPG можно использовать для проверьте эти теги:

PHP 8.2

паб rsa4096 2021-04-01 [SC]
      1198 К011 7593 497А 5ЭК5 К199 286А Ф1Ф9 8974 69ДК
uid [конечный] Пьеррик Чаррон 
суб rsa4096 2021-04-01 [E]
pub rsa4096 2021-04-26 [SC] [дата окончания: 2025-11-24]
      39B6 4134 3D8C 104B 2B14 6DC3 F9C3 9DC0 B969 8544
uid [конечный] Бен Рэмси 
sub rsa4096 2021-04-26 [E] [срок действия истекает: 2025-11-24]
pub rsa4096 2021-03-26 [SC] [срок действия истекает: 2030-03-26]
      Э609 13Э4 ДФ20 9907 Д8Э3 0Д96 659А 97К9 КФ2А 795А
uid [ultimate] Сергей Пантелеев 
uid [ultimate] Сергей Пантелеев 
uid [ultimate] Сергей Пантелеев 
sub rsa4096 2021-03-26 [E] [срок действия истекает: 2025-03-26]
   

PHP 8.1

паб 2048R/31CBD89E 2016-12-08
      Отпечаток ключа = 5289 95BF EDFB A719 1D46 839E F9BA 0ADA 31CB D89E
uid Джо Уоткинс  net>
pub rsa4096 2021-04-26 [SC] [дата окончания: 2025-11-24]
      39B6 4134 3D8C 104B 2B14 6DC3 F9C3 9DC0 B969 8544
uid [конечный] Бен Рэмси 
sub rsa4096 2021-04-26 [E] [срок действия истекает: 2025-11-24]
паб rsa4096 2021-04-01 [SC]
      F1F6 9223 8FBC 1666 E5A5 CCD4 199F 9DFE F6FF BAFD
uid [конечный] Патрик Аллаерт 
саб rsa4096 2021-04-01 [E]
   

PHP 8.0

паб 4096R/70D12172 2017-04-14 [срок действия истекает: 2024-04-21]
      Отпечаток ключа = 1729 F839 38DA 44E2 7BA0 F4D3 DBDB 3974 70D1 2172
uid Сара Големон 
pub rsa4096 2020-05-09 [SC] [срок действия истекает: 2024-05-08]
      БФДД Д286 4282 4Ф81 18ЭФ 7790 9Б67 А5К1 2229 118Ф
uid [ultimate] Габриэль Карузо (менеджер по выпуску) 
sub rsa4096 2020-05-09 [E] [срок действия истекает: 2024-05-08]
паб rsa4096 2022-08-30 [SC] [дата окончания: 2024-08-29]
      2C16 C765 DBE5 4A08 8130 F1BC 4B9B 5F60 0B55 F3B4
uid [конечный] Габриэль Карузо  net>
sub rsa4096 2022-08-30 [E] [срок действия истекает: 2024-08-29]
   

PHP 7.4

sec rsa4096 2019-06-11 [SC] [срок действия истекает: 2029-06-08]
      5А52880781Ф755608БФ815ФК910ДЕБ46Ф53ЭА312
uid [конечный] Дерик Ретанс 
uid [конечный] Дерик Ретанс 
uid [конечный] Дерик Ретанс (GitHub) 
uid [конечный] Дерик Ретанс (PHP) 
ссб rsa4096 2019-06-11 [E] [дата окончания: 2029-06-08]
pub rsa4096 2019-05-29 [SC] [срок действия истекает: 2021-05-28]
      4267 0A7F E4D0 441C 8E46 3234 9E4F DC07 4A4E F02D
uid [конечный] Питер Кокот 
sub rsa4096 2019-05-29 [E] [срок действия истекает: 2021-05-28]
   

PHP 7.3

pub rsa4096/118BCCB6 2018-06-05 [SC] [дата окончания действия: 2022-06-04]
      Отпечаток ключа = CBAF 69F1 73A0 FEA4 B537 F470 D66C 9593 118B CCB6
uid Кристоф М. Беккер 
паб 2048D/5DA04B5D 2012-03-19Отпечаток ключа = F382 5282 6ACD 957E F380 D39F 2F79 56BC 5DA0 4B5D
uid Станислав Малышев (ключ PHP)  com>
uid Станислав Малышев (ключ PHP) 
uid Станислав Малышев (ключ PHP) 
   

PHP 7.2

паб 4096R/70D12172 2017-04-14 [срок действия истекает: 2024-04-21]
      Отпечаток ключа = 1729 F839 38DA 44E2 7BA0 F4D3 DBDB 3974 70D1 2172
uid Сара Големон 
паб 4096R/EE5AF27F 2017-05-24 [дата окончания: 2024-05-22]
      Отпечаток ключа = B1B4 4D8F 021E 4E2D 6021 E995 DC9F F8D3 EE5A F27F
uid Реми Колле 
pub rsa4096/118BCCB6 2018-06-05 [SC] [дата окончания действия: 2022-06-04]
      Отпечаток ключа = CBAF 69F1 73A0 FEA4 B537 F470 D66C 9593 118B CCB6
uid Кристоф М. Беккер 
   

PHP 7.1

паб 4096R/7BD5DCD0 07.05.2016
      Отпечаток ключа = A917 B1EC DA84 AEC2 B568 FED6 F50A BC80 7BD5 DCD0
uid Дэйви Шафик 
паб 2048R/31CBD89E 2016-12-08
      Отпечаток ключа = 5289 95BF EDFB A719 1D46 839E F9BA 0ADA 31CB D89E
uid Джо Уоткинс 
паб 4096R/70D12172 2017-04-14 [срок действия истекает: 2024-04-21]
      Отпечаток ключа = 1729 F839 38DA 44E2 7BA0 F4D3 DBDB 3974 70D1 2172
uid Сара Големон  net>
   

PHP 7.0

паб 2048R/9C0D5763 09.06.2015 [срок действия истекает: 06.06.2024]
      Отпечаток ключа = 1A4E 8B72 77C4 2E53 DBA9 C7B9 BCAA 30EA 9C0D 5763
uid Анатолий Бельский 
публикация 2048R/33CFC8B3 14 января 2014 г. [дата окончания действия: 13 января 2020 г.]
      Отпечаток ключа = 6E4F 6AB3 21FD C07F 2C33 2E3A C2BF 0BC4 33CF C8B3
uid Ференц Ковач 
   

PHP 5.6

публикация 2048R/33CFC8B3 14 января 2014 г. [дата окончания действия: 13 января 2020 г.]
      Отпечаток ключа = 6E4F 6AB3 21FD C07F 2C33 2E3A C2BF 0BC4 33CF C8B3
uid Ференц Ковач 
паб 2048R/90D90EC1 2013-07-18 [срок действия: 2016-07-17]
      Отпечаток ключа = 0BD7 8B5F 9750 0D45 0838 F95D FE85 7D9A 90D9 0EC1
uid Жюльен Паули 
   

PHP 5.5

паб 2048R/90D90EC1 2013-07-18 [срок действия: 2016-07-17]
      Отпечаток ключа = 0BD7 8B5F 9750 0D45 0838 F95D FE85 7D9A 90D9 0EC1
uid Жюльен Паули  net>
публикация 4096R/7267B52D 20 марта 2012 г. [дата окончания действия: 19 марта 2016 г.]
      Отпечаток ключа = 0B96 609E 270F 565C 1329 2B24 C13C 70B8 7267 B52D
uid Дэвид Сориа Парра 
паб 2048D/5DA04B5D 2012-03-19
      Отпечаток ключа = F382 5282 6ACD 957E F380 D39F 2F79 56BC 5DA0 4B5D
uid Станислав Малышев (ключ PHP) 
uid Станислав Малышев (ключ PHP) 
uid Станислав Малышев (ключ PHP) 
   

PHP 5.4

паб 2048D/5DA04B5D 2012-03-19
      Отпечаток ключа = F382 5282 6ACD 957E F380 D39F 2F79 56BC 5DA0 4B5D
uid Станислав Малышев (ключ PHP) 
uid Станислав Малышев (ключ PHP) 
uid Станислав Малышев (ключ PHP) 
   

PHP 5.3

публикация 4096R/7267B52D 20 марта 2012 г. [дата окончания действия: 19 марта 2016 г.]
      Отпечаток ключа = 0B96 609E 270F 565C 13292Б24 К13К 70Б8 7267 Б52Д
uid Дэвид Сориа Парра 
паб 2048R/FC9C83D7 18 марта 2012 г.  [дата окончания действия: 17 марта 2017 г.]
      Отпечаток ключа = 0A95 E9A0 2654 2D53 835E 3F3A 7DEC 4E69 FC9C 83D7
uid Йоханнес Шлютер 
uid Йоханнес Шлютер 
   

Брелок для ключей

Вы можете загрузить связку ключей со всеми открытыми ключами Release Manager: php-keyring.gpg [38Kb]

Возможности и улучшения PHP 7

Ура! PHP 7 наконец-то вышел, и чтобы отпраздновать его выпуск, я создал видео, в котором рассказывается о нескольких интересных функциях PHP 7.

Содержание

  • 1 Новые функции PHP 7: Быстрый обзор
  • 2 Скалярные подсказки типа
  • 3 Объявления типа возврата
  • 4 Анонимные классы
  • 5 Закрытие :: Call () Метод
  • 6 Generation Degation
  • 7 Выражения возврата генератора
  • 8 Оператор объединения с нулевым значением
  • 9 Оператор космического корабля
  • 10 броски
  • 11 Уровень поддержки для функции Dirname ()
  • 12 Функция целочисленного деления
  • 13 Однородные переменные синтаксис
  • 14 Производительность
  • 15 Мы PHP 7 Готов

Новые функции PHP 7: краткий обзор

Посмотрите видео, в нем рассказывается о нескольких функциях PHP 7, которые мне нравятся. Вот список вещей, которые я освещаю:

  • Подсказки скалярного типа
  • Объявления типа возврата
  • Анонимные классы
  • The Closure :: Call () Method
  • Деятор генератор
  • Генератор. () function
  • Функция деления целых чисел
  • Синтаксис унифицированных переменных

Подсказки скалярного типа

Подсказки типов уже доступны в PHP. К сожалению, они были ограничены классами, массивами и вызываемыми объектами.

Начиная с PHP 7, скалярные типы (целые числа, числа с плавающей запятой, логические значения и строки) также могут использоваться в качестве подсказок типа.

Посмотреть код на Gist.

Я доволен этой функцией PHP 7, потому что она позволяет разработчикам обеспечить лучшую согласованность ввода интерфейса функции/метода. По умолчанию «принудительный режим» включен. Это не позволяет PHP выдавать ошибку типа, когда типы не совсем совпадают, но когда преобразование все еще возможно.

Если вы включите «строгий режим» (раскомментировав строку 6) , выдается ошибка типа, когда подписи не совпадают.

Объявления возвращаемых типов

В то время как подсказки типов обеспечивают согласованность ввода, объявления возвращаемых типов обеспечивают согласованность вывода.

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

Посмотреть код на Gist.

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

Анонимные классы

Анонимные классы полезны для простых одноразовых объектов. С помощью анонимных классов вы можете определить класс и создать встроенный экземпляр объекта.

Посмотреть код на Gist.

Метод Closure::call()

Замыкания — это анонимные функции, которые объявляются встроенными и назначаются переменной. Его можно использовать в качестве обратного вызова для последующего выполнения. В PHP 5 уже можно было привязать объект к области замыкания, как если бы это был метод.

Метод «вызов» — это одна из функций PHP 7, которая была введена для упрощения процесса.

Посмотреть код на Gist.

Делегация генератора

Генераторы — это круто, но иногда их трудно объяснить. Как ни странно, использовать их на удивление просто. Все дело в ключевом слове «доходность». Используя «выход», генератор возвращает полученное значение. Генератор реализует итератор, который упрощает использование в , в то время как или для петель.

В PHP 7 было введено делегирование генератора. Это означает, что можно обратиться к генератору из другой функции.

Посмотреть код на Gist.

Выражения, возвращаемые генератором

Как уже упоминалось: с помощью ключевого слова yield можно получить значения и выполнить итератор. Но возвращаемые значения игнорируются генераторами.

В PHP 7 метод getReturn  был добавлен в класс Generator, чтобы разрешать возвращаемые значения в генераторах.

Посмотреть код на Gist.

Оператор слияния с нулевым значением

Оператор слияния с нулевым значением – это сокращение для проверки установленного значения, а не нулевого, в рамках встроенных сравнений. Вместо того, чтобы снова и снова выполнять одну и ту же проверку «isset» , просто используйте «??» , чтобы вернуть значение, если оно установлено (а не ноль), или альтернативное значение.

Посмотреть код на Gist.

Оператор космического корабля

Так называемый «Оператор космического корабля» упрощает сравнение значений. Вместо типичного значения true/false оператор космического корабля возвращает одно из следующих значений в зависимости от результата оценки: значение меньше правого значения

  • 1 если левое значение больше правого
  • См. код в Gist.

    Throwables

    Большое изменение в PHP 7 заключается в том, что ошибки больше не вызываются так, как раньше. Ошибки теперь ведут себя аналогично исключениям. Оба они наследуются от интерфейса Throwable.

    Это означает, что теперь ошибки можно перехватывать в блоке try/catch . Вы можете перехватывать как исключения, так и ошибки как Throwables, но вы также можете перехватывать ошибки как объекты Error.

    Существуют события различных типов ошибок, которые мы можем отловить:

    • ArithmeticError
    • AssertionError
    • DivisionByZeroError
    • ParseError
    • TypeError

    ist.

    Это также нарушение обратной совместимости , поскольку пользовательские обработчики ошибок могут не запускаться. Если у вас есть ошибка синтаксического анализа в функции eval, она выдаст ошибку ParseError, а не просто вернет false. Осторожно!

    Уровень поддержки функции dirname()

    Функция dirname используется чаще, чем вы думаете. Это идеальная функция для ссылки на каталоги относительным образом.

    Но когда вы хотите подняться на пару уровней выше, вы в конечном итоге вкладываете вызовы dirname, что в конечном итоге приводит к путанице.

    Начиная с PHP 7 функция dirname имеет второй аргумент, который указывает, на сколько уровней вы поднимаетесь по дереву каталогов. Если вы не введете значение, по умолчанию будет 1.

    Посмотреть код на Gist.

    Функция целочисленного деления

    Возможно, это не самая важная функция PHP 7, но все же стоит упомянуть: функция intdiv возвращает целочисленное значение деления, тогда как обычные деления могут привести к возвращению числа с плавающей запятой.

    Посмотреть код на Gist.

    Унифицированный синтаксис переменных

    В PHP 7 появился «унифицированный синтаксис переменных». Этот стандарт изменяет способ оценки косвенного доступа к ключам, свойствам и методам массива. Интерпретация PHP 7 обеспечивает строгую оценку слева направо.

    Это также считается нарушением обратной совместимости. Если вы хотите, чтобы ваш код работал на PHP 7, рекомендуется изменить код и использовать фигурные скобки, чтобы обеспечить соблюдение порядка оценки.

    Производительность

    Не забываем упомянуть, что производительность PHP 7 должна быть впечатляющей. Некоторые говорят, что он в два раза быстрее, чем PHP 5(.6), другие используют еще более впечатляющие цифры. Я уверен, что он отлично работает, и мне любопытно увидеть средние цифры, когда люди начнут его использовать.

    Некоторые источники говорят, что он даже превосходит HHVM. Но не забывайте слова ложь, наглая ложь и статистика.

    Я взволнован, посмотрим.

    Мы готовы к PHP 7

    В Combell, хостинговой компании, в которой я работаю, мы некоторое время тестировали PHP 7. Мы большие поклонники возможностей PHP 7. Мы уже сделали PHP 7.0.0 RC8 доступным в нашей панели управления, и теперь мы предлагаем PHP 7.0.x на виртуальном хостинге.