
Ожидается, что следующий выпуск 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 не поддерживается, потому что он бесполезен и имеет нечеткую семантику.
Вызываемый тип не поддерживается, поскольку его поведение зависит от контекста.
Таким образом , мы можем смело использовать bool
, int
, float
, string
, array
, object
, iterable
, self
, parent
, любой класс или имя интерфейса, и обнуляемые тип ( ?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_dump
NULL
Ковариантные возвраты и контравариантные параметры
Дисперсия — это свойство иерархий классов, описывающее, как типы конструктора типов влияют на подтипы. В общем случае конструктор типа может быть:
- Инвариант: если тип супертипа ограничивает тип подтипа.
- Ковариант: если порядок типов сохраняется (типы упорядочены от более специфических к более общим).
- 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.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 5 до сих пор используется 52,4% всех веб-сайтов с известным языком программирования на стороне сервера. Если вы добавите число пользователей, все еще использующих PHP 7.0 , окажется, что подавляющее большинство веб-сайтов используют неподдерживаемые версии PHP.

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

Мы настоятельно рекомендуем запрашивать у вашего хостинга поддерживаемую версию 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 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-запроса обычно показывает версию.

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

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