Что нового в PHP 7.4 (особенности, устаревшие возможности, производительность)

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

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

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

  • 6 июня: PHP 7.4 Alpha 1
  • 18 июля: PHP 7.4 Beta 1 — Замораживание функций
  • 28 ноября: релиз PHP 7.4 GA

Вы можете ознакомиться с полным списком функций и дополнений на официальной странице RFC.

Дата выхода PHP 7.4

Релиз PHP 7.4 запланирован на 28 ноября 2019 года. Это следующий минорный релиз PHP 7, который должен еще раз повысить производительность и улучшить читаемость / удобство сопровождения кода.

Что нового в PHP 7.4?

PHP 7.4 — это предстоящий дополнительный выпуск, который сделает PHP быстрее и надежнее. 

Забудьте array_merge: в PHP 7.4 будет оператор Spread

Доступна начиная с PHP 5.6, распаковка аргументов — это синтаксис для распаковки массивов и Traversables в списки аргументов. Чтобы распаковать массив или объект Traversable, он должен начинаться с… (3 точки), как показано в следующем примере:

function test(...$args) { var_dump($args); }
test(1, 2, 3);

Теперь этот PHP 7.4 RFC предлагает расширить эту функцию до определений массивов:

$arr = [...$args];

Первое заявленное преимущество Spread Operator в выражении массива связано с производительностью. На самом деле, документ RFC гласит :

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

Существенным преимуществом оператора Spread является то, что он поддерживает любые перемещаемые объекты, а array_mergeфункция поддерживает только массивы.

Вот пример распаковки аргумента в выражении массива:

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);

Если вы запустите этот код в PHP 7.3 или более ранней версии, PHP выдаст ошибку Parse:

Parse error: syntax error, unexpected '...' (T_ELLIPSIS), expecting ']' in /app/spread-operator.php on line 3

Вместо этого PHP 7.4 будет возвращать массив:

array(5) {
	[0]=>
	string(6) "banana"
	[1]=>
	string(6) "orange"
	[2]=>
	string(5) "apple"
	[3]=>
	string(4) "pear"
	[4]=>
	string(10) "watermelon"
}

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

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];

Также возможно распаковать возвращенные функцией массивы непосредственно в новый массив:

function buildArray(){
	return ['red', 'green', 'blue'];
}
$arr1 = [...buildArray(), 'pink', 'violet', 'yellow'];

PHP 7.4 выводит следующий массив:

array(6) {
	[0]=>
	string(3) "red"
	[1]=>
	string(5) "green"
	[2]=>
	string(4) "blue"
	[3]=>
	string(4) "pink"
	[4]=>
	string(6) "violet"
	[5]=>
	string(6) "yellow"
}

Мы также можем использовать синтаксис генератора :

function generator() {
	for ($i = 3; $i <= 5; $i++) {
		yield $i;
	}
}
$arr1 = [0, 1, 2, ...generator()];

Но нам не разрешается распаковывать массивы, переданные по ссылке. Рассмотрим следующий пример:

$arr1 = ['red', 'green', 'blue'];
$arr2 = [...&$arr1];

Если мы попытаемся распаковать массив по ссылке, PHP выдаст следующую ошибку Parse:

Parse error: syntax error, unexpected '&' in /app/spread-operator.php on line 3

В любом случае, если элементы первого массива хранятся по ссылке, они также сохраняются по ссылке и во втором массиве. Вот пример:

$arr0 = 'red';
$arr1 = [&$arr0, 'green', 'blue'];
$arr2 = ['white', ...$arr1, 'black'];

И вот что мы получаем с PHP 7.4:

array(5) {
	[0]=>
	string(5) "white"
	[1]=>
	&string(3) "red"
	[2]=>
	string(5) "green"
	[3]=>
	string(4) "blue"
	[4]=>
	string(5) "black"
}

Стрелочные функции 2.0 (короткие замыкания)

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

Рассмотрим следующий пример:

function cube($n){
	return ($n * $n * $n);
}
$a = [1, 2, 3, 4, 5];
$b = array_map('cube', $a);
print_r($b);

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

$a = [1, 2, 3, 4, 5];
$b = array_map(fn($n) => $n * $n * $n, $a);
print_r($b);

В настоящее время анонимные функции (замыкания) могут наследовать переменные, определенные в родительской области, благодаря useязыковой конструкции, как показано ниже:

$factor = 10;
$calc = function($num) use($factor){
	return $num * $factor;
};

Но в PHP 7.4 переменные, определенные в родительской области видимости, неявно фиксируются по значению (неявная привязка области по значению). Таким образом, мы можем записать всю функцию, представленную выше, в одну строку:

$factor = 10;
$calc = fn($num) => $num * $factor;

Переменная, определенная в родительской области видимости, может использоваться в стрелочной функции точно так же, как если бы мы ее использовали , и невозможно изменить переменную из родительской области видимости.use($var)

Новый синтаксис является большим улучшением языка, поскольку он позволяет нам создавать более читаемый и обслуживаемый код. Мы также можем использовать параметры и возвращаемые типы , значения по умолчанию, списки аргументов переменной длины ( функции с переменным числом аргументов ), мы можем передавать и возвращать по ссылке и т. Д. Наконец, короткие замыкания также могут использоваться в методах класса, и они могут использовать $thisпеременной как обычные закрытия.

Оператор присваивания нулевого слияния

Оператор coalesce ( ??), добавленный в PHP 7, удобен, когда нам необходимо использовать троичный оператор вместе с isset(). Возвращает первый операнд, если он существует и не существует NULL. В противном случае он возвращает второй операнд. Вот пример:

$username = $_GET['user'] ?? ‘nobody';

То, что делает этот код, довольно просто: он выбирает параметр запроса и устанавливает значение по умолчанию, если его не существует . Смысл этой строки ясен, но что если бы у нас были гораздо более длинные имена переменных, как в этом примере из RFC?

$this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value';

В конечном счете, этот код может быть немного сложен в обслуживании. Таким образом, с целью помочь разработчикам писать более интуитивно понятный код, этот RFC предлагает ввести оператор присваивания нулевого слияния ( ??=). Таким образом, вместо написания предыдущего кода мы могли бы написать следующее:

$this->request->data['comments']['user_id'] ??= ‘value’;

Если значение левого параметра равно null, то используется значение правого параметра.
Обратите внимание, что, хотя оператор объединения является оператором сравнения, ??=это оператор присваивания.

Типизированные Свойства 2.0

Объявления типов аргументов или подсказки типов позволяют указывать тип переменной, которая, как ожидается, будет передана в функцию или метод класса. Подсказки типов доступны с PHP 5, а с PHP 7.2 мы можем использовать их с objectтипом данных. Теперь PHP 7.4 предлагает намек на шаг вперед, добавляя поддержку объявлений типов свойств первого класса. Вот очень простой пример:

class User {
	public int $id;
	public string $name;
}

Поддерживаются все типы, за исключением voidи callable:

public int $scalarType;
protected ClassName $classType;
private ?ClassName $nullableClassType;

RFC объясняет причину voidи callableне поддерживается:

Тип void не поддерживается, потому что он бесполезен и имеет нечеткую семантику.

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

Таким образом , мы можем смело использовать boolintfloatstringarrayobjectiterableselfparent, любой класс или имя интерфейса, и обнуляемые тип ( ?type).

Типы могут быть использованы для статических свойств:

public static iterable $staticProp;

Они также допускаются с varпометкой:

var bool $flag;

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

public string $str = "foo";
public ?string $nullableStr = null;

Один и тот же тип применяется ко всем свойствам в одном объявлении:

public float $x, $y;

Что произойдет, если мы сделаем ошибку в типе свойства? Рассмотрим следующий код:

class User {
	public int $id;
	public string $name;
}

$user = new User;
$user->id = 10;
$user->name = [];

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

Fatal error: Uncaught TypeError: Typed property User::$name must be string, array used in /app/types.php:9

Слабые ссылки

В этом RFC PHP 7.4 вводит класс WeakReference, который позволяет сохранять ссылку на объект, который не препятствует уничтожению самого объекта.

В настоящее время PHP поддерживает Weak References, используя расширение вроде pecl-weakref. В любом случае, новый API отличается от документированного WeakRefкласса.

Вот пример от автора этого предложения, Никиты Попова:

$object = new stdClass;
$weakRef = WeakReference::create($object);

var_dump($weakRef->get());
unset($object);
var_dump($weakRef->get());

Первый var_dumpпечатает , а второй печатает , так как указанный объект был уничтожен.object(stdClass)#1 (0) {}var_dumpNULL

Ковариантные возвраты и контравариантные параметры

Дисперсия — это свойство иерархий классов, описывающее, как типы конструктора типов влияют на подтипы. В общем случае конструктор типа может быть:

  • Инвариант: если тип супертипа ограничивает тип подтипа.
  • Ковариант: если порядок типов сохраняется (типы упорядочены от более специфических к более общим).
  • Contravariant: если он меняет порядок (типы упорядочены от более общих к более конкретным).

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

Вот пример ковариантного типа возвращаемого значения :

interface Factory {
	function make(): object;
}

class UserFactory implements Factory {
	function make(): User;
}

А вот пример контравариантного типа параметра :

interface Concatable {
	function concat(Iterator $input); 
}
 
class Collection implements Concatable {
	// accepts all iterables, not just Iterator
	function concat(iterable $input) {/* . . . */}
}

Посмотрите RFC для более детального изучения ковариации и контравариантности в PHP 7.4.

Предзагрузка

Это предложение Дмитрия Стогова должно значительно повысить производительность. Предварительная загрузка — это процесс загрузки библиотек и фреймворков в OPCache при инициализации модуля (подробнее о жизненном цикле PHP ).

Жизненный цикл PHP

Вот как работает предварительная загрузка:

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

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

Предварительная загрузка управляется определенной php.iniдирективой: opcache.preload. Эта директива указывает PHP-скрипт, который будет скомпилирован и выполнен при запуске сервера. Этот файл может использоваться для предварительной загрузки дополнительных файлов, включая их или через opcache_compile_file()функцию (подробнее см. Документацию PHP ).

Но есть и обратная сторона. На самом деле RFC прямо заявляет:

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

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

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

Новый механизм сериализации пользовательских объектов

В настоящее время у нас есть два различных механизма для настраиваемой сериализации объектов в PHP:

  • __sleep()И __wakeup()магические методы
  • Serializableинтерфейс

Оба этих варианта имеют проблемы, которые приводят к сложному и ненадежному коду. Вы можете углубиться в эту тему в RFC . Новый механизм сериализации должен предотвратить эти проблемы, предоставляя два новых магических метода, __serialize()и __unserialize(), которые сочетают в себе два существующих механизма.

Устаревшие функции

Следующие функции / функциональные возможности будут устаревшими с PHP 7.4. 

Изменение приоритета оператора конкатенации

В настоящее время в PHP арифметические операторы «+» и «-» и строковый оператор «.» остаются ассоциативными и имеют одинаковый приоритет.

В качестве примера рассмотрим следующую строку:

echo "sum: " . $a + $b;

В PHP 7.3 этот код выдает следующее предупреждение:

Warning: A non-numeric value encountered in /app/types.php on line 4

Это потому, что конкатенация оценивается слева направо. Это то же самое, что написать следующий код:

echo ("sum: " . $a) + $b;

Этот RFC предлагает изменить приоритет операторов, давая «.» Более низкий приоритет, чем операторы «+» и «-», так что сложения и вычитания всегда будут выполняться до объединения строк. Эта строка кода должна быть эквивалентна следующей:

echo "sum: " . ($a + $b);

Это двухэтапное предложение:

  • Начиная с версии 7.4, PHP должен выдавать уведомление об устаревании при обнаружении выражения без скобок с «+», «-» и «.».
  • Фактическое изменение приоритета этих операторов должно быть добавлено в PHP 8.

Левоассоциативный троичный оператор

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

В настоящее время в PHP следующий код является правильным:

$b = $a == 1 ? 'one' : $a == 2 ? 'two' : $a == 3 ? 'three' : 'other';

Это интерпретируется как:

$b = (($a == 1 ? 'one' : $a == 2) ? 'two' : $a == 3) ? 'three' : 'other';

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

Это еще одно двухэтапное предложение:

  • Начиная с PHP 7.4, вложенные троичные без явного использования скобок будут выдавать предупреждение об устаревании.
  • Начиная с PHP 8.0, во время выполнения будет ошибка компиляции.

Что означает PHP 7.4 для пользователей WordPress?

PHP является наиболее широко используемым серверным языком программирования в сети. Согласно W3Techs , по состоянию на 28 мая 2019 года использование PHP все еще растет:

Версии PHP

К сожалению, PHP 5 до сих пор используется 52,4% всех веб-сайтов с известным языком программирования на стороне сервера. Если вы добавите число пользователей, все еще использующих PHP 7.0 , окажется, что подавляющее большинство веб-сайтов используют неподдерживаемые версии PHP.

Поддерживаемые версии PHP

Согласно официальной  странице статистики WordPress , на момент написания этой статьи, на 67% всех веб-сайтов WordPress работают неподдерживаемые версии PHP. Только немногим более 3% используют последнюю версию: PHP 7.3 . Вы можете видеть, что подавляющее большинство пользователей, более 31%, все еще работают на PHP 5.6.

Версии WordPress PHP

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

  • Версия PHP 7.3 или выше.
  • MySQL версии 5.6 или выше ИЛИ MariaDB версии 10.1 или выше.
  • Поддержка HTTPS

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

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

  • Официальные тесты PHP показывают, что PHP 7 позволяет системе выполнять в два раза больше запросов в секунду по сравнению с PHP 5.6, почти с половиной задержки.
  • Кристиан Виг также опубликовал  сравнение производительности PHP,  в котором он обнаружил, что PHP 5.2 на 400% медленнее, чем PHP 7.
  • Андрей Аврам увидел более быстрое время выполнения и меньшее использование памяти в PHP 7.4 , чем в PHP 7.3
  • Phoronix провел несколько ранних тестов производительности с PHP 7.4 Alpha и увидел, что он немного быстрее PHP 7.3.

Мы запустили наши собственные  тесты производительности PHP с PHP 7.3. Мы увидели, что WordPress 5.0 на PHP 7.3 может выполнять почти в три раза больше транзакций (запросов) в секунду по сравнению с PHP 5.6. Мы скоро выпустим тесты PHP 7.4!

Тесты WordPress 5.0 PHP

Тесты WordPress 5.0 PHP

  • Тест WordPress 5.0 PHP 5.6: 91,64 запросов / сек
  • Результаты тестов WordPress 5.0 PHP 7.0: 206,71 запросов / сек
  • Результаты тестов WordPress 5.0 PHP 7.1: 210,98 запросов / сек
  • Результаты тестов WordPress 5.0 PHP 7.2: 229,18 запросов / сек
  • WordPress 5.0  PHP Результаты тестов: 7,3 253,20 запросов / сек  🏆

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

Проверка вашей версии PHP

Не уверены, какую версию PHP вы используете? Один из самых простых способов проверить это — использовать такой инструмент, как  Pingdom  или Google Chrome Devtools. Первый заголовок HTTP-запроса обычно показывает версию.

Проверьте версию PHP в Pingdom

Это зависит от того, что хостинг не изменяет  X-Powered-Byзначение заголовка. Тем не менее, многие делают из-за соображений безопасности. Если это так, вы можете не увидеть свою версию PHP. В этом случае, если вы используете WordPress 5.2 или выше, есть новый инструмент Site Health, который вы можете использовать. Перейдите в «Инструменты» → «Состояние сайта» → «Информация» и в разделе «Сервер» вы найдете версию PHP вашего сервера.

Проверьте версию PHP с помощью WordPress Site Health.

Проверьте версию PHP с помощью WordPress Site Health.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Scroll to top