Что нового в PHP 8: все, что вам нужно знать!

Опубликовано: 2021-01-06

Мы свяжемся с PHP8 26 ноября 2020 года, и, конечно же, много написано о предстоящих функциях в этом ценном выпуске.

PHP 8

Поскольку это основная версия, в нее будут внесены критические изменения и новые функции, а также важно знать, что все меняется. Будет удобно подумать о том, как PHP8 повлияет на ваши приложения и какие действия необходимо предпринять, чтобы обеспечить удобное обновление без происшествий.

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

начнем с обзора!

Обзор PHP 8

Как упоминалось выше, в PHP 8 представлен ряд новых возможностей, улучшений, функций и исключений из языка. Среди всего этого наиболее обсуждаемой функцией является JIT-компилятор. Тем не менее, функции повышения производительности, такие как JIT, заслуживают внимания, а синтаксические улучшения, как ожидается, окажут большее влияние на практиков PHP, мы бы сказали, «по крайней мере, в краткосрочной перспективе».

История изменений

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

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

Кредиты попадают прямо в категорию типов. Впервые они были предложены в 2016 году для PHP 7.1. Однако они встретили упорное сопротивление и с большим отрывом проиграли голосование. Теперь, перенесемся на четыре года вперед, и довольно похожее предложение, хотя и с немного уменьшенным объемом, было принято всего с одним несогласным. Очевидно, это идея, время которой определенно пришло!

Какие проблемы со старым кодом?

Поскольку PHP 8 — это огромная новая версия, мы должны ожидать, что старый код больше не будет совместим. Однако большинство изменений, которые могли вызвать сложности, уже были внесены в версии 7.2 , 7.3 и 7.4 . Теперь поговорим о последних изменениях. Они:

Волшебные цитаты наследия

  • Настоящий тип
  • Фильтр FILTER_SANITIZE_MAGIC_QUOTES
  • Отвязка $this от нестатических замыканий
  • array_key_exists() с объектами
  • mb_strrpos() с кодировкой в ​​качестве третьего аргумента
  • Методы экспорта() отражения
  • функция convert_cyr_string()
  • смесь порядка параметров implode()
  • функция restore_include_path()
  • функция hebrevc()
  • функция money_format()
  • директива allow_url_include ini
  • функция ezmlm_hash()

Новые функции в PHP 8

str_contains

Если одна строка содержит другую, то есть множество способов узнать это.

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

Теперь, когда он возвращает позицию строки в другой строке, вы просто не можете проверить, обнаружила ли ее функция strpos(); если он возвращает «0» (позиции имеют нулевой индекс и начинаются с 0, а не с 1), то условное выражение будет рассматривать его как ложное значение и указывать, что оно не было найдено.

Что это значит?

Вам нужно будет написать условие – «strpos($haystack, $needle) !== false». False указывает, что не удалось найти позицию строки. Это непрозрачный и эзотерический метод поиска строки в строке! Ну, не так запутанно.

Чтобы избежать этого, в PHP 8 появилась функция str_contains(). Задача str_contains() состоит в том, чтобы вернуть простое логическое значение, показывающее, присутствует ли иголка в стоге сена. Это намного проще писать, кроме того, понимать, что кто-то поддерживает код, не так ли?

 if (str_contains( 'Foo Bar Baz' , 'Foo' )) { // FOUND }

PHP 8: особенности и изменения движка

Есть некоторые новые функции движка и изменения, замеченные в PHP 8. Главной особенностью, несомненно, является новый JIT-компилятор.

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

  • Правоприменение LSP
  • Фатальные ошибки при несовместимых сигнатурах методов
  • Ресурс «Классы»
  • XML-RPC теперь в PECL
  • Поведение утверждения
  • Изменения отражения

Ради основной цели этого блога мы сосредоточимся на JIT-компиляторе, «классах» ресурсов и, наконец, на изменениях API отражения.

Компилятор Just-In-Time ( RFC )

Из-за улучшений скорости, сделанных до выпуска PHP7, произошло рождение компилятора Just-In-Time (или JIT). Он вводится в PHP8, потому что почти нет улучшений в скорости, которые можно было бы внести без использования JIT. Идея состоит в том, что это улучшит производительность PHP.

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

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

Это отражает то, что PHP-приложения на стороне сервера, безусловно, могут быть более распространены со встроенной в PHP JIT-системой.

Сначала вам нужно активировать JIT, если вы хотите его использовать. В нашей тестовой системе (Ubuntu 20.04) мы уже установили модуль PHP opcache, который мы установили вместе с основным пакетом PHP8. Мы настроили в файле, расположенном по адресу /etc/php/8.0/cli/conf.d/10-opcache.ini.

Теперь все готово для активации JIT, верно?  

  • Включить оперативный кэш

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

  1. zend_extension=opcache.so
  2. opcache.enable_cli=1
  3. ; конфигурация модуля php opcache
  4. opcache.jit_buffer_size=256M

Кроме того, используйте функцию opcache_get_status(), чтобы убедиться, что она активна. Проведите взглядом по части «jit» этого массива и получите информацию о текущем статусе JIT.


var_dump(opcache_get_status()['jit']);

Если JIT был активирован правильно, это должно распечататься, как показано ниже.

  1. массив (7) {
  2. ["включено"]=>
  3. логический (правда)
  4. ["включено"]=>
  5. логический (правда)
  6. ["добрый"]=>
  7. интервал(5)
  8. ["opt_level"]=>
  9. интервал (4)
  10. ["opt_flags"]=>
  11. интервал(6)
  12. ["размер_буфера"]=>
  13. интервал (268435440)
  14. ["buffer_free"]=>
  15. интервал (268432880)
  16. }

Так было быстрее? Одним словом, мы бы воскликнули теплое «да».

Мы заметили, что несколько человек проводят тесты с помощью набора Мандельброта, поэтому мы решили использовать библиотеку, которую мы создали некоторое время назад, которая рисует различные виды фракталов в PHP. Все, что мы сделали, это сгенерировали три фрактала и отследили, сколько времени это заняло, используя функцию microtome(). Мы отобразили результаты для PHP 7.4.8 ниже.

  • Бёрнингшип — 84.20269203186
  • Мандельброт — 21.552599906921
  • Трикорн — 32,685042858124

Когда мы запускали тот же самый код на PHP8, он работал намного быстрее . Цифры скажут сами за себя. .

  • Горящий корабль — 15.272277116776
  • Мандельброт -3,7528541088104
  • Треуголка -4.4957919120789

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

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

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

Типы союзов ( RFC )

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

В PHP8 теперь можно указать различные виды аргументов и возвращаемых значений, разделенных вертикальной чертой.

Ниже мы показали функцию, способную принимать как вещественное, так и целочисленное значение.

 function addNumbers(int|float $number1, int|float $number2) : int|float { return $number1 + $number2; }

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

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

 echo addNumbers(1, 1); // prints 2 echo addNumbers(1.1, 1.1); // prints 2.2

В случае, если мы попытаемся передать строку в идентичную функцию:

 echo addNumbers('one', 'two');

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

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

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

Оператор Nullsafe (RFC)

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

Итак, мы можем сделать это, чтобы получить значение из «$_GET superglobal». а если этого значения нет, то «0».


1. $page = $_GET['page'] ?? 0;

2. повторить $страницу;

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

Мы заметили, что это будет в конечном счете полезно в Drupal, где мы, как правило, пишем большую часть кода проверки, чтобы убедиться, что «возвраты из методов» или «свойства объекта» имеют в себе что-то перед их использованием. Это обязательно из-за контекстуального состояния объектов в Drupal из-за содержимого, которое они содержат. Это изменение наверняка упростит некоторые проверки.

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

Именованные аргументы позволяют указать другой порядок аргументов и функций вызова. Возьмите следующую нормальную функцию с двумя параметрами. Он заполняет массив заданной длины.

 function fillArray(array $arrayToFill, int $number) : array { for ($i = 0 $i < $number; ++$i) { $arrayToFill[$i] =1; } return $arrayToFill; }

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

 $newArray = fillArray([], 2);

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

 $newArray = fillArray(number: 2, arrayToFill: []);

Обычный пример, но он также может сделать код более читабельным.

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

Атрибуты V2 ( RFC1 RFC2 RFC3 )

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

Класс ReflectionClass присутствует в PHP начиная с PHP5; однако метод getAttribute() является новым для PHP8. Этот метод возвращает ряд объектов ReflectionAttribute, которые будут содержать информацию об атрибутах.

Это дополнение претерпело несколько изменений (как мы можем заметить из нескольких RFC выше). Если вы создаете экземпляр класса, вы можете использовать ReflectionClass и распечатать информацию об атрибуте, содержащуюся на уровне класса. Атрибутов в PHP8 довольно много, поэтому мы рекомендуем прочитать RFC и ознакомиться с тем, что они собой представляют на самом деле и как вы можете интегрировать их в свой код.

Выражение совпадения ( RFC )

В PHP 8 мы можем сравнить новое выражение соответствия с сокращенным оператором switch.

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

Оператор switch в PHP великолепен, когда вы хотите проверить условие для идентичного выражения, не включая несколько операторов if .

Здесь мы приводим базовое сравнение if-else для идентичного выражения.

 <?php if ($i == 'apple') { echo 'i is apple'; } elseif ($i == 'cake') { echo 'i is cake'; } else { echo 'i is pizza'; }

И вот как будет выглядеть эквивалентный оператор switch из нашего предыдущего примера:

 <?php switch ($i) { case 'apple': echo 'i is apple'; break; case 'cake': echo 'i is cake'; break; default: echo 'i is pizza'; }

Ресурс «Классы»

«Классы» ресурсов входят в список основных изменений в PHP 8 и служат неинстанцируемой заменой для заданных типов ресурсов. Ниже приведены доступные замены:

  • CurlHandle — curl_init() теперь возвращает CurlHandle, относящийся к ресурсу curl.
  • Socket / AddressInfo — Задается расширением сокетов; количество функций socket_*() возвращает Socket, а функция socket_address_info_lookup() возвращает экземпляр AddressInfo.
  • GdImage — представляет ресурс GD, восстановленный многочисленными функциями imagecreatefrom*().

Кроме того, важно отметить, что ресурсы не уничтожаются такими функциями, как curl_close(). Скорее, вам нужно unset() экземпляра, чтобы разыменовать его, поскольку теперь он является экземпляром класса.
Вы получаете возможность указывать классы как подсказки типов в своих функциях и методах.
Раньше нам приходилось возвращать значения нетипизированными или оставлять аргументы ресурсов и документировать их с помощью аннотаций, но теперь у вас могут быть явные типы, и это не только делает ваш код более читабельным, но и более типобезопасным.
Какой компромисс здесь?
Теперь вам нужно обновить свой код, если вы хотите уничтожить ресурсы с помощью unset() вместо предыдущих функций, используемых для уничтожения ресурсов. Обычно это можно сделать с помощью поиска и замены.

Изменения API отражения

Еще одно небольшое, но жизненно важное изменение в PHP 8 связано с Reflection API. При использовании системы атрибутов вы можете удобно получать эти атрибуты через API Reflection для любых классов отражения.
С добавлением смешанных типов и типов объединения методы ReflectionParameter getClass(), isCallable() и isArray() теперь устарели.
Сценарий таков, потому что использование getType() намного лучше, и вы получаете полный список типов, которым удовлетворяет конкретный параметр.

Улучшения синтаксиса PHP 8

Как мы заметили, JIT ворует заголовки; синтаксические улучшения PHP 8 обеспечивают огромные преимущества качества жизни для PHP-разработчиков.
Независимо от того, устраняется ли общий шаблон среди продвигаемых аргументов конструктора или улучшена обработка исключений и ошибок, разработчики могут быть в восторге от многих вещей.

  • «смешанный» псевдотип
  • Типы союзов
  • Продвижение свойства Class Constructor
  • Генерация исключений из выражений
  • Атрибуты
  • :: классовая вездесущность
  • Поймать только по типу
  • Совпадение выражений

Для поддержания целей этого блога мы сосредоточимся на типах объединения, атрибутах и ​​выражениях соответствия.

Типы союзов

Типы объединения показывают, что значение является одним из двух или более указанных типов. Это делается с помощью вертикальной черты, помещенной между каждым разрешенным типом. Для нескольких разработчиков, которые глубоко разбираются в аннотациях PHP, чтобы возвращать значения или указывать свои параметры, вы, скорее всего, уже делали это.
Типы объединения могут создать большую сложность и трудности для понимания для тех, кто принимает много разных типов или возвращает много разных типов.
Тем не менее, это будет очень полезно в нескольких случаях. Например, если вы можете принять либо объект, реализующий новый интерфейс Stringable («string|Stringable»), либо строку, либо если вы можете принять либо объект, реализующий интерфейс Traversable («array|Traversable»), либо массив .

Совпадение выражений

Выражения сопоставления отсекают догадки, связанные с выяснением того, является ли сбой в данном случае переключения преднамеренным или нет. Это также упрощает обычный шаблон присвоения значения на основе совпадения.
При использовании значение, которое мы передаем в match(), будет напрямую сравниваться с любым выражением в левой части. Независимо от того, является ли это выражением или значением, значение, которое вы передаете в match(), должно совпадать с ним, чтобы оно было выбрано.
При совпадении оценивается выражение, представленное справа, и возвращается его возвращаемое значение, в то время как выражения могут быть только лямбда-функциями или вызываемыми функциями, а многострочные замыкания не допускаются.

Атрибуты

PHP 8 также интегрирует атрибуты на уровне языка. Хотя атрибуты присутствуют в аннотациях докблоков уже более 15 лет, их встраивание в язык обеспечивает лучшую производительность и, безусловно, большую мощность и большую согласованность. Скорее всего, мы увидим, что атрибуты широко используются при разработке инструментов и быстрых приложений.

Вывод

Конечно, в PHP8 есть некоторые изменения. Тем не менее, похоже, что большая часть удаляемого устаревшего кода относится к более старым функциям, которые мы не видели в последнее время.
Нам очень интересно узнать, какое влияние JIT-движок окажет на кодовые базы, которые мы используем, а также на более широкое PHP-сообщество. Мы настоятельно рекомендуем сканировать вашу кодовую базу на предмет несовместимости с PHP8 и запускать модульные тесты, чтобы убедиться, что ваш PHP приложения работают отлично, прежде чем сказать «да» обновлению.