Что нового в PHP 7.4
PHP 7.4 - последняя версия перед PHP 8, содержит множество дополнений и исправлений синтаксиса, будет выпущен 28 ноября 2019 года. Пост создан для помощи в подготовки к предстоящим изменениям.
PHP 7.4 будет содержать немало новых возможностей, начнем с новых функций, а затем рассмотрим изменения и устаревание функционала.
Короткие замыкания RFC
Короткие замыкания допускают менее подробный синтаксис анонимной функции. Вместо многословного:
array_map(function (User $user) {
return $user->id;
}, $users)
можно использовать более лаконичное выражение:
array_map(fn(User $user) => $user->id, $users)
Согласитесь, выглядит здорово?!
Несколько замечаний:
- Короткие замыкания могут получить доступ к родительской области, ключевое слово use - не нужно.
- $this доступен так же, как и у обычных замыканий.
- Такие замыкания могут содержать в теле только одну строку, которая также является оператором возврата.
Предварительная загрузка (Preloading) RFC
Предварительная загрузка - удивительное дополнение к ядру PHP, которое может привести к значительному улучшению производительности.
Итак, если вы в своей работе используете какой-либо фреймворк, его файлы должны быть загружены и перекомпилированы при каждом запросе. Предварительная загрузка позволяет серверу загружать PHP-файлы в память при запуске и иметь их постоянно доступными для всех последующих запросов.
Предварительная загрузка управляется директивой opcache.preload в файле php.ini. Эта директива указывает PHP-скрипт, который будет скомпилирован и выполнен при запуске сервера. Данный файл может использоваться для предварительной загрузки дополнительных файлов или через функцию opcache_compile_file() (подробнее см. Документацию PHP).
Повышение производительности, конечно, связано с некоторым условием: если источник предварительно загруженных файлов изменяется, сервер должен быть перезапущен.
Типизированные свойства RFC
Переменные класса могут быть подсказаны типом:
<?php
class A
{
public string $name;
public Foo $foo;
}
Это очень долгожданное со времён PHP 7 изменение в направлении более строгой типизации языка. Теперь у нас есть все основные возможности для строгой типизации.Для типизации доступны все типы, за исключением void и callable.
Улучшена разница типов RFC
Разница типов - это тема, достойная отдельного сообщения в блоге ; короче говоря: вы сможете использовать противоречивые типы возврата
class ParentType {}
class ChildType extends ParentType {}
class A
{
public function covariantReturnTypes(): ParentType
{ /* … */ }
}
class B extends A
{
public function covariantReturnTypes(): ChildType
{ /* … */ }
}
... и противоречивые аргументы.
class A
{
public function contraVariantArguments(ChildType $type)
{ /* … */ }
}
class B extends A
{
public function contraVariantArguments(ParentType $type)
{ /* … */ }
}
RFC в настоящее время находится на этапе голосования, но, похоже, пройдет без проблем
Интерфейс внешней функции RFC
Интерфейс внешней функции, FFI, позволяет вызывать код C из пользовательского пространства. Это означает, что расширения PHP могут быть написаны на чистом PHP.
Следует отметить, что это сложная тема. Вам все еще нужны знания C, чтобы правильно использовать эту функцию.
Оператор присваивания значения NULL RFC
Появится возможность использовать синтаксис "если левый параметр не существует или равен null, присвоить ему значение правого параметра".
Т.е. вместо этого:
$data['date'] = $data['date'] ?? new DateTime();
Вы можете сделать это:
$data['date'] ??= new DateTime();
Оператор распаковки (...) в массивах RFC
Теперь можно использовать оператор распаковки в массивах:
$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; //[1, 2, 3]
$arr3 = [0, ...$arr1]; //[0, 1, 2, 3]
$arr4 = array(...$arr1, ...$arr2, 111); //[1, 2, 3, 1, 2, 3, 111]
$arr5 = [...$arr1, ...$arr1]; //[1, 2, 3, 1, 2, 3]
Это работает только с массивами с числовыми ключами, с ассоциативными массивами распаковка работать не будет, ошибка будет выдана при обнаружении строкового ключа. Оператор спреда должен иметь лучшую производительность, чем array_merge. Это объясняется не только тем, что оператор распаковки является языковой структурой, в то время как array_merge является функцией, но и оптимизация времени компиляции может быть выполнена для констант массива. Плюс array_merge поддерживает операции только над массивами, а оператор спреда поддерживает реализацию объектов Traversable.
Пользовательская сериализация объектов RFC
В настоящее время PHP предоставляет два механизма для настраиваемой сериализации объектов: методы __sleep()/__wakeup() и Serializable интерфейс. К сожалению, по словам Никиты, оба подхода имеют проблемы., которые приводят к сложному и ненадежному коду Этот RFC добавляет два новых магических метода: __serialize и __unserialize, которые позволяют избежать этих проблем
// Returns array containing all the necessary state of the object.
public function __serialize(): array;
// Restores the object state from the given data array.
public function __unserialize(array $data): void;
Использование очень похоже на Serializable интерфейс. С практической точки зрения главное отличие состоит в том, что вместо вызова serialize() внутри Serializable::serialize() вы напрямую возвращаете данные, которые должны быть сериализованы в виде массива. В следующем примере показано, как __serialize()/__unserialize() используются и как они составляются при наследовании:
class A {
private $prop_a;
public function __serialize(): array {
return ["prop_a" => $this->prop_a];
}
public function __unserialize(array $data) {
$this->prop_a = $data["prop_a"];
}
}
class B extends A {
private $prop_b;
public function __serialize(): array {
return [
"prop_b" => $this->prop_b,
"parent_data" => parent::__serialize(),
];
}
public function __unserialize(array $data) {
parent::__unserialize($data["parent_data"]);
$this->prop_b = $data["prop_b"];
}
}
Разделитель числовых литералов RFC
Отсутствие визуальных разделителей в группах цифр увеличивало время чтения и отладки кода, и могло привести к непреднамеренным ошибкам. Теперь добавлена поддержка символа подчёркивания в числовых литералах для визуального разделения групп цифр.
1_000_000_000 // int
6.674_083e-11; // float
299_792_458; // decimal
0xCAFE_F00D; // hexadecimal
0b0101_1111; // binary
0137_041; // octal
Рефлексия для ссылок RFC
Такие библиотеки как var dumper Symfony, в значительной степени полагаются на API Рефлексии для надежного вывода переменной. Раньше не было должной поддержки рефлексии для ссылок, в результате чего эти библиотеки полагались на "хаки" для обнаружения ссылок.
PHP 7.4 добавляет класс ReflectionReference, который решает эту проблему.
Обновление 02-14: RFC пройден, и изменения подтверждены для PHP 7.4.
Такие библиотеки как var dumper Symfony, в значительной степени полагаются на API Рефлексии для надежного вывода переменной. Раньше не было должной поддержки рефлексии для ссылок, в результате чего эти библиотеки полагались на "хаки" для обнаружения ссылок.
PHP 7.4 добавляет класс ReflectionReference, который решает эту проблему.
Обновление 02-14: RFC пройден, и изменения подтверждены для PHP 7.4.
Слабые ссылки
Слабые ссылки - это ссылки на объекты, которые не мешают их уничтожению. 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) {} , а потом выведет NULL , так как указанный объект был уничтожен.
Слабые ссылки - это ссылки на объекты, которые не мешают их уничтожению. 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) {} , а потом выведет NULL , так как указанный объект был уничтожен.
Добавлена функция mb_str_split RFC
Эта функция обеспечивает те же функциональные возможности, что str_split и для многобайтовых строк.
Реестр хэширования паролей RFC
Внутренние изменения в библиотеке хеширования, чтобы пользователям было проще использовать хэширование. Добавлена новая функция password_algos, которая возвращает список всех зарегистрированных алгоритмов хеширования паролей
Изменения и устаревание
Помимо новых функций, есть также много изменений в языке. Большинство этих изменений не нарушают работу программиста, хотя некоторые из них могут повлиять на уже написанный вами код.
Обратите внимание, что предупреждения об устаревании не являются критическими, а просто уведомляют разработчика о том, что функциональность будет удалена или изменена в будущем. Было бы хорошо не игнорировать предупреждения об устаревании и сразу же их исправлять; поскольку это сделает путь обновления для PHP 8.0 более простым.
Приоритет при конкатенации RFC
Эта функция обеспечивает те же функциональные возможности, что str_split и для многобайтовых строк.
Реестр хэширования паролей RFC
Внутренние изменения в библиотеке хеширования, чтобы пользователям было проще использовать хэширование. Добавлена новая функция password_algos, которая возвращает список всех зарегистрированных алгоритмов хеширования паролей
Изменения и устаревание
Помимо новых функций, есть также много изменений в языке. Большинство этих изменений не нарушают работу программиста, хотя некоторые из них могут повлиять на уже написанный вами код.
Обратите внимание, что предупреждения об устаревании не являются критическими, а просто уведомляют разработчика о том, что функциональность будет удалена или изменена в будущем. Было бы хорошо не игнорировать предупреждения об устаревании и сразу же их исправлять; поскольку это сделает путь обновления для PHP 8.0 более простым.
Если бы вы написали что-то вроде этого:
echo "sum: " . $a + $b;
PHP ранее интерпретировал бы это так:
echo ("sum: " . $a) + $b;
PHP 8 сделает так, чтобы он интерпретировался так:
echo "sum :" . ($a + $b);
В PHP 7.4 при обнаружении выражения без скобок, добавлено предупреждение об устаревании синтаксиса, содержащего «.» перед «+» или «-».
Разрешены исключения в __toString RFC
Ранее исключения не могли быть добавлены в магический метод__toString. Они были запрещены из-за некоторых старых механизмов обработки ошибок, правда Никита Попов отметил, что это «решение» на самом деле не решило проблему, которую он пытался решить.
RFC все еще находится на стадии голосования, но с 32 голосами за и 0 против, можно с уверенностью сказать, что это пройдет.
ext-hash всегда включен RFC
Как видно из заголовка, это расширение теперь постоянно доступно во всех установках PHP.
PEAR по умолчанию больше не включен ВНЕШНЕЕ
Поскольку PEAR больше не поддерживается, основная команда решила удалить установку по умолчанию с PHP 7.4.
Устареет ext/wwdx RFC
Этот формат обмена данными никогда не был стандартизирован, и теперь его расширение устарело.
Короткие теги PHP устарели RFC
Короткий открытый тег <? устарел и будет удален в PHP 8. Короткий echo тег <?= оставлен.
array_merge и array_merge_recursive без аргументов
Поскольку добавлен оператор распаковки (...), теперь имеет смысл использовать array_merge так:
$merged = array_merge(...$arrayOfArrays);
Теперь array_merge и array_merge_recursive позволяют передавать пустой список параметров. Пустой массив будет возвращен, если не было передано ни одного массива.
strip_tags принимает массивы
Ранее несколько тегов можно было бы удалить только перечислением тегов в строке:
strip_tags($string, '<a><p>')
PHP 7.4 позволяет использовать массив:
strip_tags($string, ['a', 'p'])
Лево-ассоциативный тернарный оператор устареет RFC
Тернарный оператор имеет некоторые странные особенности в PHP. Этот RFC добавляет статус деприкейт для вложенных троичных операторов. В PHP 8 это устаревание будет преобразовано в ошибку времени при компиляции.
//устареет
1 ? 2 : 3 ? 4 : 5;
//нормально
(1 ? 2 : 3) ? 4 : 5;
Устарели фигурные скобки для доступа к массивам и строкам
Раньше можно было получить доступ к массивам и смещениям строк, используя фигурные скобки:
$array{1};
$string{3};
Теперь лучше от этого отказаться.
Улучшение в proc_open улучшения
Были внесены изменения, чтобы proc_open мог выполнять программы, не проходя через shell. Это делается путем передачи массива вместо строки для команды.
Список некоторых устаревших вещей
- Тип real
- Magic quotes legacy
- array_key_exists() с объектами
- FILTER_SANITIZE_MAGIC_QUOTES фильтр
- Метод Reflection export()
- mb_strrpos() с указанием кодировки 3 аргументом
- implode() параметр порядка смешивания
- Открепление $this от нестатических замыканий ($closure->bindTo(null))
- функция hebrevc()
- функция convert_cyr_string()
- функция money_format()
- функция ezmlm_hash()
- функция restore_include_path()
- директива ini allow_url_include
Обратно несовместимые изменения
Так же не забываем смотреть на полный документ обновлений версий PHP.
Можно выделить следующие несовместимых назад изменений:
- Вызов parent:: в классе без родителя вызовет ошибку.
- Использование var_dump для DateTime или DateTimeImmutable больше не будет выводить доступные свойства объекта.
- openssl_random_pseudo_bytes сгенерирует исключение в случае ошибки. Раньше она возвращала false, что могло привести к генерации пустой строки.
- Попытка сериализации экземпляров PDO или PDOStatement сгенерирует Exception вместо PDOException.
- Вызов get_object_vars() для ArrayObject экземпляре будет возвращать свойства самого ArrayObject, а не значения обернутого массива или объекта. Чтобы как раньше получить значения обернутого массива — приведите ArrayObject к типу array
Изменились правила голосования RFC RFC
Технически это не обновление, связанное с PHP 7.4, хотя это, безусловно, стоит упомянуть. Правила голосования для RFC были изменены: для принятия RFC требуется 2/3 голосов, все RFC должны быть открыты не менее 2 недель, чтобы пройти одобрение.
Что думаешь?