Перевод статьи подготовлен в преддверии старта курса «Backend-разработчик на PHP»

(Читать первую часть)


PHP 7.2

Расширение типа параметра

<?php

class ArrayClass {
 public function foo(array $foo) { /* … / }
}

// Этот RFC предлагает разрешить расширение типа до нетипизированного, т.е. в качестве параметра может быть передан любой тип.
// Любые ограничения типа могут быть отработаны с помощью пользовательского кода в теле метода.
class EverythingClass extends ArrayClass {
 public function foo($foo) { / … / }
}

Подсчет неисчислимых объектов

Вызов функции count() для скаляра или объекта, который не реализует интерфейс Countable возвращает 1 (что нелогично).

В этой версии добавлено предупреждение при вызове count() с параметром, который является скаляром, null или объектом, который не реализует Countable.

Завершающие запятые в групповом use синтаксисе 

use Foo\Bar{ Foo, Bar, Baz, };

Хеширование пароля с помощью Argon2

Существующие функции password_* обеспечивают упрощенный интерфейс с прямой совместимостью для хеширования паролей. Этот RFC предлагает для использования в функциях password_* реализацию Argon2i (v1.3) в качестве безопасной альтернативы.

Отладка эмуляции подготовленного запроса PDO

$db = new PDO(…);

// работает с запросами без связанных значений
$stmt = $db->query('SELECT 1');
var_dump($stmt->activeQueryString()); // => string(8) "SELECT 1"

$stmt = $db->prepare('SELECT :string');
$stmt->bindValue(':string', 'foo');

// возвращает не распаршенный запрос до выполнения
var_dump($stmt->activeQueryString()); // => string(14) "SELECT :string"

// возвращает распаршенный запрос после выполнения
$stmt->execute();
var_dump($stmt->activeQueryString()); // => string(11) "SELECT 'foo'"

PHP 7.3

JSON_THROW_ON_ERROR

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

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

Вот пример:

json_decode("{");

json_lasterror() === JSONERRORNONE // результат false

json_lasterrormsg() // результат "Syntax error"

Итак, давайте же посмотрим, как мы можем использовать этот новый синтаксический сахар:

use Json_Exception;

try {
   $json = json_encode("{", JSON_THROW_ON_ERROR);
   return base64_encode($json);
} catch (JsonException $e) {
   throw new EncryptException('Could not encrypt the data.', 0, $e);
}

Как видно из предыдущего кода, функция json_encode теперь имеет необязательный параметр JSON_THROW_ON_ERROR - с ним она перехватит ошибку и отобразит ее с помощью следующих методов исключений:

$e->getMessage(); // как json_lasterrormsg()

$e->getCode(); // как json_lasterror()

Добавлена функция is_countable

// До:
if (is_array($foo) || $foo instanceof Countable) {
  // $foo является countable
}

// После

if (is_countable($foo)) {
  // $foo является countable
}

Добавлены функции массива array_key_first(), array_key_last()

$firstKey = array_key_first($array);
$lastKey = array_key_last($array);

Добавлена ​​встроенная поддержка “samesite” cookie

Теперь есть две опции для cookie, использующего флаг samesite: «Lax» (нестрогий) и «Strict» (строгий). Разница между Lax и Strict заключается в доступности файла cookie в запросах, исходящих из другого регистрируемого домена с использованием метода HTTP GET. Файлы cookie, использующие Lax, будут доступны по GET, исходящему из другого регистрируемого домена, тогда как файлы cookie, использующие Strict, не будут доступны в GET запросе. Для POST методов разницы нет: браузер не должен разрешать доступ к cookie в POST запросе, исходящем из другого регистрируемого домена.

Set-Cookie: key=value; path=/; domain=example.org; HttpOnly; SameSite=Lax|Strict

Обновление PCRE до PCRE2

Улучшение хеширования паролей с помощью Argon2

Существующие password_* функции обеспечивают упрощенный интерфейс с прямой совместимостью для хеширования паролей. Этот RFC предлагает для использования в password_* функциях реализацию Argon2id в качестве безопасной альтернативы первоначально предложенному Argon2i.

Завершающая запятая в вызовах функций

$newArray = array_merge(
   $arrayOne,
   $arrayTwo,
   ['foo', 'bar'],// в вызовах функций можно использовать запятую
);

Присвоение по ссылкам в list()

$array = [1, 2];
list($a, &$b) = $array;

Это эквивалентно следующему:

$array = [1, 2];
$a = $array[0];
$b =& $array[1];

Устарели не чувствительные к регистру константы

PHP 7.4 

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

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

   public function __construct(int $id, string $name) {
       $this->id = $id;
       $this->name = $name;
   }
}

FFI (Foreign Function Interface)

FFI - одна из фич, которые сделали Python и LuaJIT очень полезными для быстрого прототипирования. Он позволяет вызывать функции C и использовать типы данных C из чисто скриптового языка и, следовательно, более продуктивно разрабатывать «системный код». Для PHP FFI открывает способ писать расширения PHP и биндинги к библиотекам C на чистом PHP.

Присваивающий оператор объединения с Null

// Следующие строчки делают одно и то же
$this->request->data['comments']['userid'] = $this->request->data['comments']['userid'] ?? 'value';
// Вместо повторения переменных с длинными именами используется присваивающий оператор объединения
$this->request->data['comments']['user_id'] ??= 'value';

Предварительная загрузка

PHP использует кеши опкодов уже много лет (APC, Turck MMCache, Zend OpCache). Они дают значительный прирост производительности, ПОЧТИ полностью устраняя накладные расходы на перекомпиляцию PHP кода. Предварительная загрузка будет контролироваться только одной новой директивой php.ini - opcache.preload. Используя эту директиву, мы определяем PHP файл, который возьмет на себя задачу предварительной загрузки. После загрузки этот файл полностью выполняется - и может предварительно загружать другие файлы, инклюдя их или используя функцию opcache_compile_file() .

Всегда доступное хеш расширение

Это делает хеш расширение (ext/hash) всегда доступным, схожим образом с date. Хеш расширение предоставляет очень ценную утилиту со множеством алгоритмов хеширования, которая чрезвычайно полезна в современных приложениях, причем не только в коде юзерленда, но и во многих случаях во внутреннем коде.

На пути к PHP 8.0

JIT

В двух словах, когда вы запускаете PHP программу, Zend Engine парсит код в абстрактное синтаксическое дерево (abstract syntax tree - AST) и преобразует его в опкоды. Опкоды - это единицы выполнения для виртуальной машины Zend (Zend VM). Опкоды довольно низкоуровневые, поэтому их гораздо быстрее переводить в машинный код, чем исходный код PHP. В ядре PHP есть расширение OPcache для кеширования этих опкодов.

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

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

Стабильные typeErrors для внутренних функций

Сделайте так, чтобы API синтаксического анализа внутренних параметров всегда генерировали TypeError, если синтаксический анализ завершается неудачно. Следует отметить, что это также включает ArgumentCountError (дочерний элемент TypeError) для случаев, когда было передано слишком мало/много аргументов.

Сравнение производительности

Я составил простой тест, который поможет легко сравнить производительность различных версий PHP (с использованием Docker). Он даже позволил бы легко проверять производительность новых версий PHP, просто добавляя новые имена контейнеров.

Тестировалось на Macbook pro, Intel Core i7 2,5 ГГц.

PHP version : 5.6.40
--------------------------------------
test_math                 : 1.101 sec.
test_stringmanipulation   : 1.144 sec.
test_loops                : 1.736 sec.
test_ifelse               : 1.122 sec.
Mem: 429.4609375 kb Peak mem: 687.65625 kb
--------------------------------------
Total time:               : 5.103

PHP version : 7.0.33
--------------------------------------
test_math                 : 0.344 sec.
test_stringmanipulation   : 0.516 sec.
test_loops                : 0.477 sec.
test_ifelse               : 0.373 sec.
Mem: 421.0859375 kb Peak mem: 422.2109375 kb
--------------------------------------
Total time:               : 1.71

PHP version : 7.1.28
--------------------------------------
test_math                 : 0.389 sec.
test_stringmanipulation   : 0.514 sec.
test_loops                : 0.501 sec.
test_ifelse               : 0.464 sec.
Mem: 420.9375 kb Peak mem: 421.3828125 kb
--------------------------------------
Total time:               : 1.868

PHP version : 7.2.17
--------------------------------------
test_math                 : 0.264 sec.
test_stringmanipulation   : 0.391 sec.
test_loops                : 0.182 sec.
test_ifelse               : 0.252 sec.
Mem: 456.578125 kb Peak mem: 457.0234375 kb
--------------------------------------
Total time:               : 1.089

PHP version : 7.3.4
--------------------------------------
test_math                 : 0.233 sec.
test_stringmanipulation   : 0.317 sec.
test_loops                : 0.171 sec.
test_ifelse               : 0.263 sec.
Mem: 459.953125 kb Peak mem: 460.3984375 kb
--------------------------------------
Total time:               : 0.984

PHP version : 7.4.0-dev
--------------------------------------
test_math                 : 0.212 sec.
test_stringmanipulation   : 0.358 sec.
test_loops                : 0.205 sec.
test_ifelse               : 0.228 sec.
Mem: 459.6640625 kb Peak mem: 460.109375 kb
--------------------------------------
Total time:               : 1.003

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

meskis/php-bench

Бенчмарки от PHP 5.6 и выше

Мне очень понравилась компиляция визуальной производительности всех основных версий от 5.6 и выше от servebolt.com. См. результаты в таблицах ниже.

Сводка по производительности

PHP 7.0.0 стал важной вехой со значительно улучшенной производительностью и меньшим использованием памяти, но у специалистов по сопровождению уже PHP попросту заканчиваются идеи по его улучшению. Один из оставшихся моментов - JIT (Just in time) компиляция. И она придет с PHP 8.0.

Направление развития

В версиях PHP 7.x прослеживается путь к более типизированному (и немного более объектному) и современному языку программирования. PHP любит перенимать изящные и полезные функции других языков программирования.

Вскоре мы можем увидеть еще несколько замечательных функций, таких как:

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

TL;DR

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

Ссылки

https://wiki.php.net/rfc

https://www.cloudways.com/blog/php-5-6-vs-php-7-symfony-benchmarks/

https://servebolt.com/articles/wordpress-5-0-php-7-2-vs-php-7-3-performance-and-speed-benchmark/


Узнать подробнее о курсе.