PHP постоянно развивается, и только что мир увидело их последнее обновление — PHP 7.4. Производительность и скорость продолжают расти, в чём мы убедились ещё в предыдущих релизах PHP 7. Предварительная загрузка — одно из самых ярких обновлений. Эта возможность позволяет значительно ускорить выполнение скрипта и делает код чище и быстрее благодаря уменьшённому количеству строк кода.
PHP является важным элементом всемирной паутины и используется более чем на 79% всех сайтов. Известные сайты, такие как Facebook, Википедия, WordPress и многие другие используют PHP.
Мы можем увидеть что скорость веб-сайтов WordPress увеличивается вдвое, если сравним сайты, работающие на PHP 5 и 7. От последней версии больше всего выиграют сайты на WordPress.
![](https://habrastorage.org/webt/q6/kr/ln/q6krln_loh5ukxndokhwhmiosja.png)
В настоящее время PHP используют около 40 млн. сайтов. Этот график иллюстрирует производительность сайтов, которые активно используют PHP. В целом, PHP 7.4 выглядит довольно неплохо по сравнению с PHP 7.3: лучшая производительность, к которой добавились возможности FFI, функция предварительной загрузки и другие улучшения.
На следующем графике сравниваются общие результаты теста производительности 7.4 и более старых версий PHP.
![](https://habrastorage.org/webt/wy/r5/hd/wyr5hdsls_v5ry-tu-nw6xsm04w.png)
PHP 7.4: Что Нового?
Постоянные ежегодные обновления PHP7 начали выходить с 2016 года: различные новые функции, возможность писать более чистый код, чтобы сделать язык более надёжным и удобным, если вы запускаете его на своём сайте и т.д. Давайте взглянем на некоторые модификации, которые появились с выходом версии PHP 7.4.
Полный список изменений можно посмотреть в их ченджлоге.
Предварительная Загрузка
Предварительная загрузка — позволяет загружать фреймворки и библиотеки в OPCache. Это действительно удобная функция, поскольку при каждом использовании файлов или библиотек необходимо загружать и связывать файлы по каждому запросу. Загружает файлы PHP и хранит их в памяти, чтобы они были готовы к любым поступающим запросам — вот, что делает эта фича!
Предварительная загрузка контролируется единственной новой директивой php.ini: opcache.preload. Используя эту директиву, мы можем указать один файл PHP — тот, который будет выполнять задачу предварительной загрузки. После загрузки этот файл полностью выполняется и может предварительно загружать другие файлы, либо включая их, либо используя функцию opcache_compile_file ().
Как уже было упомянуто выше, предварительно загруженные файлы будут закешированны в памяти opcache на неопределённый срок. Модификация их соответствующих исходных файлов не будет иметь никакого эффекта без перезапуска другого сервера.
Поэтому, если вам захочется снова использовать эти предварительно загруженные файлы, они будут доступны для любых предстоящих запросов.
Оператор Spread Вместо array_merge
PHP начал поддерживать распаковку аргументов (Оператор Spread), начиная с версии PHP 5.6. Теперь, с выходом 7.4, мы можем использовать оператор Spread в массивах. Синтаксис для распаковки массивов и Traversables в списки аргументов называется распаковкой аргументов. И чтобы это произошло, вам нужно всего лишь добавить три точки (…) в начале.
Взгляните на этот пример:
$tropicalfruits = ['banana', 'orange'];
$fruits = ['apple', 'pear', ...$tropicalfruits, 'plum'];
// [‘apple’, ‘pear’, ‘banana’, ‘orange’, ‘plum’];
Теперь мы также можем расширить массив другим массивом с любого места, используя синтаксис оператора Spread.
Более длинный пример:
$num1 = [1, 2, 3];
$num2 = [...$num1]; // [1, 2, 3]
$num3 = [0, ...$num1]; // [0, 1, 2, 3]
$num4 = array(...$num1, ...$num2, 111); // [1, 2, 3, 1, 2, 3, 111]
$num5 = [...$num1, ...$num1]; // [1, 2, 3, 1, 2, 3]
Кроме того, вы можете использовать его в функции. Как в этом примере:
function getNum() {
return ['x', 'y'];
}
$num6 = [...getNum(), 'z']; // ['x', 'y', 'z']
$num7 = [...new NumIterator(['x', 'y', 'z'])]; // ['x', 'y', 'z']
function arrGen() {
for($i = 11; $i < 15; $i++) {
yield $i;
}
}
$num8 = [...arrGen()]; // [11, 12, 13, 14]
Также вы можете распаковывать массивы и генераторы, которые возвращаются функцией, прямо в новый массив:
function getFruits(){
return ['apple', 'orange', 'banana'];
}
$num1 = [...getFruits(), 'plum', 'grapefruit', 'watermelon'];
PHP 7.4 выводит следующий массив:
array(6) {
[0]=>
string(3) "apple"
[1]=>
string(3) "orange"
[2]=>
string(8) "banana"
[3]=>
string(4) "plum"
[4]=>
string(5) "grapefruit"
[5]=>
string(7) "watermelon"
}
Используя это выражение массива, операторы спреда должны иметь лучшую производительность по сравнению с 7.3 array_merge. Это связано с тем, что оператор Spread является языковой структурой, а array_merge — функцией. Другая причина заключается том, что оператор спреда поддерживает реализацию объектов Traversable, в то время как array_merge поддерживает только массивы.
Ещё одна потрясающая и действительно удобная функция, которая появилась в 7.4 — это удаление индексированных массивов array_merge. Строковые ключи не поддерживаются. Больше никаких смещений индекса!
$array = [‘dog, ‘cat’];
$array[2] = ‘cat’;
$array[1] = ‘giraffe’; //shifting
var_dump($array);
// prints
array(3) {
[0]=>
string(6) "dog"
[1]=>
string(5) "giraffe"
[2]=>
string(6) "cat"
Ещё одним преимуществом PHP 7.4 является функциии-генераторы. Разница между генератором и обычной функцией заключается в том, что функция-генератор будет перебирать столько значений, сколько необходимо, вместо того, чтобы возвратить одно значение. Итак, любая функция, содержащая ключевое слово yield, является функцией-генератором:
function generator() {
for ($i = 3; $i <= 5; $i++) {
yield $i;
}
}
$num1 = [0, 1, 2, ...generator()];
Слабые ссылки
В PHP 7.4 есть класс WeakReference, который позволяет сохранить ссылку на объект, не препятствующую его уничтожению. Слабые ссылки полезны для реализации кеш-подобных структур.
Не путайте WeakReference с классом WeakRef или расширением Weakref.
WeakReference {
/* Methods */
public __construct ( void )
public static create ( object $referent ) : WeakReference
public get ( void ) : ?object
}
Контравариантные Параметры и Ковариантные Возвраты
На данный момент PHP в основном использует инвариантные типы параметров и возвращаемого значения. Это подразумевает, что подтип параметра или тип возвращаемого значения также должны быть типа X, если метод имеет параметр или тип возвращаемого значения типа X.
В PHP 7.4 появляется ковариантность (порядок от конкретного к общему) и контравариантность (обратный порядок) для типов возвращаемых данных и параметров.
Давайте посмотрим на оба примера:
Ковариантный тип возвращаемых данных:
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) {/* . . . */}
}
Типизированные Свойства 2.0
Функция контроля типов (type hints) появилась ещё в PHP 5. Она позволяет указать тип переменной, которая должна быть передана функции или методу класса.
Начиная с PHP 7.2 стало возможным использовать type hints с типом данных объекта, что вселило надежду получить ещё больше возможностей.
В PHP 7.4 стаёт возможной поддержка следующего списка типов:
bool, int, float, string, array, object, iterable, self, parent
any class or interface name
?type // where "type" may be any of the above
Родительский тип может использоваться в классах, и ему не нужно иметь родительскую константу с параметром и типом возвращаемого значения.
Поддерживаются все типы, кроме void и callable. Callable был удалён, потому что его поведение зависело от контекста; а void оказался недостаточно полезным, кроме того свою роль сыграла неясная семантика типа.
Давайте взглянем на пример ниже.
Класс PHP 7.3:
class User {
/** @var int $id */
private $id;
/** @var string $name */
private $name;
public function __construct(int $id, string $name) {
$this->id = $id;
$this->name = $name;
}
public function getId(): int {
return $this->id;
}
public function setId(int $id): void {
$this->id = $id;
}
public function getName(): string {
return $this->name;
}
public function setName(string $name): void {
$this->name = $name;
}
}
В PHP 7.4 классы выглядят намного проще:
class User {
public int $id;
public string $name;
public function __construct(int $id, string $name) {
$this->id = $id;
$this->name = $name;
}
}
Поддерживаемые типы PHP 7.4:
class Example {
public int $scalarType;
protected ClassName $classType;
private ?ClassName $nullableClassType;
// Types are also legal on static properties
public static iterable $staticProp;
// Types can also be used with the "var" notation
var bool $flag;
// Typed properties may have default values (more below)
public string $str = "foo";
public ?string $nullableStr = null;
// The type applies to all properties in one declaration
public float $x, $y;
// equivalent to:
public float $x;
public float $y;
}
Стрелочные Функции 2.0
Не секрет, что анонимные функции в PHP слишком громоздкие и продолжительные, даже если речь идёт о выполнении самых простых действий. Поэтому из JavaScript были позаимствованы стрелочные функции, или короткие замыкания. Их задача оптимизировать код PHP, улучшить его читаемость.
Анонимные функции усложняют чтение кода с второстепенной функциональностью.
Вот пример анонимной функции в PHP 7.3:
function array_values_from_keys($arr, $keys) {
return array_map(function ($x) use ($arr) { return $arr[$x]; }, $keys);
}
А это легко читаемая стрелочная функция в PHP 7.4:
function array_values_from_keys($arr, $keys) {
return array_map(fn($x) => $arr[$x], $keys);
}
Следовательно, вот насколько простыми являются стрелочные функции:
fn(parameter_list) => expr
Вы видите две функции $fn1 и $fn2. Код выглядит иначе, но функции передают идентичный результат.
$c = 1;
$fn1 = fn($a) => $a + $c;
$fn2 = function ($a) use ($c)
{
return $a + $c;
};
Это также наверняка будет работать с вложенными стрелочными функциями:
$c = 1;
$fn = fn($a) => fn($b) => $a * $b + $c;
Это что-то, что было за пределами возможностей версии 7.3. Родительская функция получает $c, в то время как дочерняя функция также получает $c от родительской функции. В PHP 7.4, внешний диапазон может стать доступным в дочерней функции.
Синтаксис стрелочных функций позволяет нам использовать переменные, значения по умолчанию, параметры и типы возвращаемых данных, а также передавать и возвращать по ссылке и т. Д. Новый синтаксис является значительным улучшением языка, поскольку он позволяет нам создавать более читабельный и понятный код.
fn(array $a) => $a;
fn(): int => $a;
fn($a = 42) => $a;
fn(&$a) => $a;
fn&($a) => $a;
fn($a, ...$rest) => $rest;
Также стоит отметить, что стрелочные функции имеют самый низкий приоритет:
fn($a) => $a + $b
// is
fn($a) => ($a + $b)
// not
(fn($a) => $a) + $b
Устаревшие Функции
На данный момент приоритет операторов “.”, “+” и “-” одинаков. Любая комбинация этих операторов будет решена слева направо.
Взгляните на пример кода PHP 7.3:
echo "sum: " . $x + $y;
// would be evaluated left-to-right
echo ("sum: " . $x) + $y;
// or like this
В PHP 7.4 сложения и вычитания всегда выполняются перед стрингой, поскольку “+” и “-” имеют приоритет над “.”:
echo «sum: ». $x + $y;
// would be performed as if the code were as below.
echo «sum :». ($x + $y);
Левоассоциативный Тернарный Оператор
В отличие от большинства других языков, где тернарный оператор обрабатывается справа на лево, в PHP это происходит наоборот. Такое поведение часто сбивает разработчиков столку, поэтому было предложено использовать круглые скобки, вместо левой ассоциативности.
Давайте посмотрим на следующий пример:
return $a == 1 ? 'one'
: $a == 2 ? 'two'
: $a == 3 ? 'three'
: $a == 4 ? 'four'
: 'other';
В большинстве других языков это читается так:
return $a == 1 ? 'one'
: ($a == 2 ? 'two'
: ($a == 3 ? 'three'
: ($a == 4 ? 'four'
: 'other')))
В то время как в PHP, это читается:
return ((($a == 1 ? 'one'
: $a == 2) ? 'two'
: $a == 3) ? 'three'
: $a == 4) ? 'four'
: 'other';
Поскольку часто это оказывается не тем, чем планировалось, в результате мы получим ошибки.
Выводы
PHP 7.4 представил новые удобные функции для каждого PHP-разработчика.
Сайты WordPress и их пользователи определённо выиграют от этих улучшений. Сокращение использования памяти и быстрое время выполнения — это лишь некоторые преимущества PHP 7.4 перед старыми релизами.
PHP 7.4, безусловно, повысит как скорость, так и качество вашего рабочего процесса благодаря представленным стрелочным функциям, объявлению типов свойств первого класса и контролю типов, а также намного лучшей скорости.