Добавлена версия PHP 7.3 Что нового?
Синтаксис
- Смягчение требований к синтаксису Heredoc и Nowdoc
- Поддержка конечных запятых в вызовах функций и методов
- Ссылки в
list()
Устаревшие возможности (deprecated)
- Функция
image2wbmp()
объявлена устаревшей - Флаги
FILTER_FLAG_SCHEME_REQUIRED
иFILTER_FLAG_HOST_REQUIRED
при использованииFILTER_VALIDATE_URL
объявлены устаревшими - Регистро-независимые константы объявлены устаревшими
Новые возможности
- Опциональный выброс исключений при ошибках в функциях
json_encode
иjson_decode
- Добавление функции
is_countable()
- Добавление функций
array_key_first()
иarray_key_last()
Изменения
- Миграция с PCRE на PCRE2
Смягчение требований к синтаксису Heredoc и Nowdoc
Heredoc и Nowdoc требовали ставить закрывающий идентификатор первым в новой строке.
Пример:
$foo = <<<IDENTIFIER
the crazy dog jumps over the lazy fox
"foo" bar;
IDENTIFIER
Здесь закрывающий IDENTIFIER
должен быть первым символом на новой линии чтобы это работало. Кроме того, не должно было быть никаких других символов после закрывающего идентификатора (кроме ;
, который является необязательным).
RFC для PHP 7.3 предлагает убрать подобные требования для улучшения читабельности кода. Прежде всего чтобы добавить отступы при использовании heredoc/nowdoc
идентификаторов.
Полный список изменений в heredoc/nowdoc
синтаксисе:
- Закрывающий идентификатор необязательно должен быть первым символом в строке.
- Закрывающий идентификатор имеет отступ пробелами или табами.
- Отступ (пробелы или табы) не должен быть смешанным. Если вы это сделаете, то получите
Parse error: Invalid indentation - tabs and spaces cannot be mixed in .. on line ..
. - Точное количество пробелов/табов, используемых перед закрывающим идентефикатором будут удалены из каждой строки
heredoc/nowdoc
выражения. - Если число отступающих символов, используемых перед закрывающим идентефикатором, больше чем в любой из строк выражения, вы получите
Parse error: Invalid body indentation level (expecting an indentation level of at least ..) in .. on line ..
- несколько выражений после закрывающего идентификатора будут работать без ошибок
Вот сниппет, который использует новые возможности без нарушения новых правил:
$foo = ['foo', 'bar', <<<EOT
baz
- hello world! --
ahoy
EOT, 'qux', 'quux'
];
var_dump($foo);
На выводе будет:
array(5) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
[2]=>
string(29) "baz
- hello world! --
ahoy"
[3]=>
string(3) "qux"
[4]=>
string(4) "quux"
} `
Обратите внимание, что отступы используемые в декларации при помощи heredoc
не отображаются в выводе var_dump()
, и мы продолжили перечисление элементов массива после EOT
идентификатора.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Пока вы не используете набор идентичных heredox/nowdoc
идентификаторам символов в качестве начала строки, вы на коне.
$foo = <<<HELLO
HELLO_WORLD <-- это не будет приниматься за окончание строкового литерала
HELLOWORLD <-- и это не будет
HELLO WORLD <-- а это будет
HELLO;
Если у вас имеется heredoc/nowdoc
синтаксис подобный вышеописанному, отмечу, что с PHP 7.3, PHP воспримет первый HELLO
литерал и выдаст ошибку на следующей строке. В более ранних версиях HELLO WORLD
не воспринимался как закрывающий идентификатор для heredoc. Спасибо /u/ImSuperObjective2 с reddit за указание на это
Поддержка конечных запятых в вызовах функций и методов
Это простое изменение, которое разрешает использование конечных запятых в вызовах функций и методах. Это не влияет на декларирование.
Например, следующий синтаксис станет возможным:
// функция
foo('bar', 'baz',); // Обратите внимание на последнюю запятую после после 'baz'
В до-PHP-7.3 версиях фрагмент выше выбрасывает ошибку PHP Parse error: syntax error, unexpected ')' in .. on line ..
.
Вы не можете использовать более одной запятой в конце или использовать запятые для пропуска аргументов. В основном это изменение для функция с вариативными параметрами. Также с новыми правками синтаксис массива будет выглядеть более последовательным.
Обратите внимание, что Вы не можете использовать эту возможность в объявлениях функций/методов; это неправильно:
function foo($bar, $baz, ) { // nah, you can't do this.
}
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Никакого. Существующий код будет и дальше работать. Если у вас есть вызовы функций принимающие вариативные параметры, добавьте конечные запятые в эти места для удобства. Но использовать их везде — это явно перебор.
Ссылки в list()
Функция list()
полезна для быстрого присвоения значений переременным из массива. До версии PHP 7.3 не было возможным указать переменную по ссылке. До PHP 7.3 следующий фрагмент приводил к фатальной ошибке:
$arr = ['apple', 'orange'];
list($a, &$b) = $arr;
$b = 'banana';
echo $arr[1];
// Fatal error: [] and list() assignments cannot be by reference in .. on line ..
Ссылкаться на non-referencable
переменные нельзя: list($a, &$b) = [12, 14];
выдаст Fatal error: Cannot assign reference to non referencable value in .. on line ..
.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Нет. Вместо того чтобы использовать list()
для заполнения нескольких переменных, я бы предложил вам воспользоваться value-объектами, чтобы сделать все проще. Они все равно будут передаваться по ссылке, но сделают ваш код намного чище.
Функция image2wbmp()
объявлена устаревшей
image2wbmp()
функция из расширения GD используется для вывода изображения в формате WBMP (Wireless Bitmap). В PHP 7.3 она объявлена устаревшей в пользу функции imagewbmp()
.
Если вы используете image2wbmp()
, то просто замените название функции на imagewbmp
и все будет хорошо! Более 5,500 упоминаний image2wbmp()
на github против более 39,300 упоминаний imagewbmp()
. Похоже, команда разработчиков PHP убирает редкоиспользуемые функции, чтобы минимизировать воздействие.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Если вы используете функцию image2wbmp()
, замените вызов на imagewbmp
. Воспользуйтесь автоматизацией, которая сможет изменить это за вас.
Флаги FILTER_FLAG_SCHEME_REQUIRED
и FILTER_FLAG_HOST_REQUIRED
при использовании FILTER_VALIDATE_URL
объявлены устаревшими
Это движение вперед. Когда вы используете filter_var($var, FILTER_VALIDATE_URL)
, есть два дополнительных флага, которые можно поставить для обеспечения строгой проверки URL-адреса: FILTER_FLAG_SCHEME_REQUIRED
и FILTER_FLAG_HOST_REQUIRED
.
Начиная с версии PHP 5.2.1 оба этих флага применяются неявно вне зависимости установлены они или нет.
Если ваш код использует эти флаги, просто удалите их и будет хорошо. На данный момент существует более 5000 результатов поиска на github с их использованием.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Так как оба этих флага объявлены устаревшими, вы увидите уведомление вроде:
Deprecated: filter_var(): explicit use of FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED is deprecated in ...
Все, что вам нужно сделать — просто удалить два флага, т.к. они и так подразумеваются при использовании FILTER_VALIDATE_URL
.
Регистро-независимые константы объявлены устаревшими
Функция define()
позволяет объявить константу в регистро-независимом режиме. Вы должны явно объявить константу с учетом регистра, передав третьим параметром функции true
. Это не поведение по-умолчанию и наверняка не согласуется с возможностью объявлять константы через ключевое слово const
.
define('Foo', 'Bar', true);
Приведенный выше код будет выбрасывать уведомление об устаревании: Deprecated: define(): Declaration of case-insensitive constants is deprecated in ...
Кроме того, при попытке получить доступ к константам, которые были объявлены в режиме без учета регистра (FOO
), вы увидете довольно полезное предупреждение: Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "Foo"
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Вам придется идти в базовый код, туда где объявляются регистро-независимые константы и последовательно исправлять. Крайне маловероятно, что не будет никаких проблем с этим, потому что отловить все варианты использования довольно трудозатратно, но в результате код станет понятней.
Я не нашел на github примеры подобного использования, но как минимум Drupal и WordPress (два довольно старых и зрелых проекта в PHP) имеют регистро-независимые константы.
Опциональный выброс исключений при ошибках в функциях json_encode
и json_decode
Одно из моих любимых. Все эти годы json_encode()
и json_decode()
молчали об ошибках в PHP-переменных или json-строках, что приводило к забагованному коду. Этот случай даже был в знаменитой критике PHP: Фрактал плохого дизайна.
json_decode
возвращает null для невалидного ввода, при том, что null — абсолютно верный объект для декодируемого JSON’а. Эта функция абсолютно ненадёжна, если вы конечно не вызываетеjson_last_error
каждый раз при её использовании.
Потребовалось 6 лет после того поста в блоге и у нас появилась возможность получить ошибку о сбоях работы с json:
try {
json_decode("{", false, 512, JSON_THROW_ON_ERROR);
}
catch (\JsonException $exception) {
echo $exception->getMessage(); // выводит "Syntax error"
}
Новый \JsonException
является наследником от \Exception
, а также константа JSON_THROW_ON_ERROR
и сам JsonException
находятся в глобальном пространстве имен.
Я настоятельно рекомендую вам начать использовать эту функцию. Есть сторонние библиотеки, такие как daverandom/exceptional-json, реализующие аналогичную функциональность для версий PHP 7.2 и ниже. С появлением этой функции в ядре PHP, вы можете удалить этот пакет и тонны некрасивого шаблонного кода с вызовом json_last_error()
в каждом месте где вы работаете с json.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Никакого, если вы не используете собственное исключение и/или константу с такими же именами.
Добавление функции is_countable()
В PHP 7.2 достаточно много устаревших и забагованных функций. Если вы в PHP 7.2. вызываете count()
с использованием не-countable
переменной, то PHP выведет предупреждение об этом. В общих правках было предложение проверять получаемую перменную на countable
до ее использования в count()
.
countable
-переменной является массив или объект реализующий \Countable
интерфейс. Так как при проверке будет использоваться много шаблонного кода, в PHP 7.3 появилась новая функция is_countable()
, проверяющая переменную на… ну… возможность использования с count()
.
Я написал полифил для is__countable(), если вы хотите начать использовать эту возможность уже сейчас.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Пока не объявлена своя собственная функция is_countable()
, проблем не будет.
Добавление функций array_key_first()
и array_key_last()
В PHP существует 75 различных функций для работы с массивами, но до сих пор не было простого способа получить первый и последний ключи массива без изменения указателя массива или перебора всех ключей (через array_keys()
) и затем получения первого/последнего значения.
Появились две новые функции, array_key_first()
и array_key_last()
позволяющие это делать.
В RFC также предлагалось добавить array_value_first()
и array_value_last()
, но эта часть не прошла голосование.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Если вы не объявляли свои собственные array_key_first()
и array_key_last()
функции, то проблем не возникнет.
Миграция с PCRE на PCRE2
PHP использует Perl Compatible Regular Expressions или коротко PCRE в библитеке для работы с регулярными выражениями. С версии PHP 7.2 используется 8.x версия легаси-библиотеки PCRE, а в PHP 7.3 уже будет использоваться PCRE2. Обратите внимание, что PCRE2 считается новой библитекой, хотя в значительной степени совместима с PCRE (8.x).
Новая библитека более агрессивна в валидации паттернов и может привести к ошибкам в существующем коде. Следующий фрагмент будет невалидным с PHP 7.3:
preg_match('/[\w-.]+/', '');
PHP выбросит предупреждение Warning: preg_match(): Compilation failed: invalid range in character class at offset 3
.
Проблема с шаблоном: чтобы это работало дефис должен быть перемещен в конец или экранирован.
preg_match('/[\w\-.]+/', '');
Приведенный выше код отлично отработает не только с PHP 7.3, а также и с более старыми версиями. В новом паттерне дефис экранирован -
в \-
. Это самая распространенная проблема из всех с которыми можно столкнуться при решении вопросов совместимости.
Это довольно незначительное изменение, но есть шанс, что все пойдет не так. Сообщение об ошибке указывает на точное положение символа в регулярном выражении. Убедитесь, что тщательно проверили свой код. Проверьте ваши регулярные выражения на совместимость с PCRE2 синтаксисом через Regex Buddy
или другой подобный софт. Дополнительные сведения смотрите в описании PCRE2 синтаксиса и устаревшего PCRE синтаксиса.
RFC, обсуждение на Externals.io, реализация
Влияние на обратную совместимость
Так как PCRE2 более придирчив и строг к шаблонам, некоторые из ваших preg_match()
и подобных вызовов могут не работать. Исправление варьируется от простого обновления шаблона (например, заэкранировать дефисы) до переписывания шаблонов. Убедитесь, что все ваши тесты проходят.