Хабрахабр

[Перевод] PHP 7.3. Что нового

  1. Смягчение требований к синтаксису Heredoc и Nowdoc
  2. Поддержка конечных запятых в вызовах функций и методов
  3. Ссылки в list()

  1. Функция image2wbmp() объявлена устаревшей
  2. Флаги FILTER_FLAG_SCHEME_REQUIRED и FILTER_FLAG_HOST_REQUIRED при использовании FILTER_VALIDATE_URL объявлены устаревшими
  3. Регистро-независимые константы объявлены устаревшими

  1. Опциональный выброс исключений при ошибках в функциях json_encode и json_decode
  2. Добавление функции is_countable()
  3. Добавление функций array_key_first() и array_key_last()

  1. Миграция с PCRE на PCRE2

Смягчение требований к синтаксису Heredoc и Nowdoc

Heredoc и Nowdoc требовали ставить закрывающий идентификатор первым в новой строке.

Пример:

$foo = <<<IDENTIFIER the crazy dog jumps over the lazy fox "foo" bar; IDENTIFIER

Кроме того, не должно было быть никаких других символов после закрывающего идентификатора (кроме ;, который является необязательным). Здесь закрывающий IDENTIFIER должен быть первым символом на новой линии чтобы это работало.

3 предлагает убрать подобные требования для улучшения читабельности кода. RFC для PHP 7. Прежде всего чтобы добавить отступы при использовании heredoc/nowdoc идентификаторов.

Полный список изменений в heredoc/nowdoc синтаксисе:

  1. Закрывающий идентификатор необязательно должен быть первым символом в строке.
  2. Закрывающий идентификатор имеет отсуп пробелами или табами.
  3. Отступ (пробелы или табы) не должен быть смешанным. Если вы это сделаете, то получите Parse error: Invalid indentation - tabs and spaces cannot be mixed in .. on line ...
  4. Точное количество пробелов/табов, используемых перед закрывающим идентефикатором будут удалены из каждой строки heredoc/nowdoc выражения.
  5. Если число отступающих символов, используемых перед закрывающим идентефикатором, больше чем в любой из строк выражения, вы получите Parse error: Invalid body indentation level (expecting an indentation level of at least ..) in .. on line ..
  6. несколько выражений после закрывающего идентификатора будут работать без ошибок

Вот сниппет, который использует новые возможности без нарушения новых правил:

$foo = ['foo', 'bar', <<<EOT baz - hello world! -- ahoy EOT, 'qux', 'quux' ]; var_dump($foo);

На выводе будет:

array(5) `

Обратите внимание, что отступы используемые в декларации при помощи heredoc не отображаются в выводе var_dump(), и мы продолжили перечисление элементов массива после EOT идентификатора.

RFC, обсуждение на Externals.io, реализация

Влияние на обратную совместимость

Пока вы не используете набор идентичных heredox/nowdoc идентификаторам символов в качестве начала строки, вы на коне.

$foo = <<<HELLO HELLO_WORLD <-- это не будет приниматься за окончание строкового литерала HELLOWORLD <-- и это не будет HELLO WORLD <-- а это будет HELLO;

3, PHP воспримет первый HELLO литерал и выдаст ошибку на следующей строке. Если у вас имеется heredoc/nowdoc синтаксис подобный вышеописанному, отмечу, что с PHP 7. Спасибо /u/ImSuperObjective2 с reddit за указание на это В более ранних версиях HELLO WORLD не воспринимался как закрывающий идентификатор для heredoc.

Поддержка конечных запятых в вызовах функций и методов

Это не влияет на декларирование. Это простое изменение, которое разрешает использование конечных запятых в вызовах функций и методах.

Например, следующий синтаксис станет возможным:

// функция
foo('bar', 'baz',); // Обратите внимание на последнюю запятую после после 'baz'

3 версиях фрагмент выше выбрасывает ошибку PHP Parse error:  syntax error, unexpected ')' in .. В до-PHP-7. on line ...

В основном это изменение для функция с вариативными параметрами. Вы не можете использовать более одной запятой в конце или использовать запятые для пропуска аргументов. Также с новыми правками синтаксис массива будет выглядеть более последовательным.

Обратите внимание, что Вы не можете использовать эту возможность в объявлениях функций/методов; это неправильно:

function foo($bar, $baz, ) { // nah, you can't do this. }

RFC, обсуждение на Externals.io, реализация

Влияние на обратную совместимость

Существующий код будет и дальше работать. Никакого. Но использовать их везде — это явно перебор. Если у вас есть вызовы функций принимающие вариативные параметры, добавьте конечные запятые в эти места для удобства.

Ссылки в list()

До версии PHP 7. Функция list() полезна для быстрого присвоения значений переременным из массива. До PHP 7. 3 не было возможным указать переменную по ссылке. 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 ..

on line ... Ссылкаться на non-referencable переменные нельзя: list($a, &$b) = [12, 14]; выдаст Fatal error: Cannot assign reference to non referencable value in ..

RFC, обсуждение на Externals.io, реализация

Влияние на обратную совместимость

Вместо того чтобы использовать list() для заполнения нескольких переменных, я бы предложил вам воспользоваться value-объектами, чтобы сделать все проще. Нет. Они все равно будут передаваться по ссылке, но сделают ваш код намного чище.

Функция image2wbmp() объявлена устаревшей

В PHP 7. image2wbmp() функция из расширения GD используется для вывода изображения в формате WBMP (Wireless Bitmap). 3 она объявлена устаревшей в пользу функции imagewbmp().

Более 5,500 упоминаний image2wbmp() на github против более 39,300 упоминаний imagewbmp(). Если вы используете image2wbmp(), то просто замените название функции на 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. Это движение вперед. 1 оба этих флага применяются неявно вне зависимости установлены они или нет. 2.

На данный момент существует более 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. Все, что вам нужно сделать — просто удалить два флага, т.к.

Регистро-независимые константы объявлены устаревшими

Вы должны явно объявить константу с учетом регистра, передав третьим параметром функции true. Функция define() позволяет объявить константу в регистро-независимом режиме. Это не поведение по-умолчанию и наверняка не согласуется с возможностью объявлять константы через ключевое слово const.

define('Foo', 'Bar', true);

Приведенный выше код будет выбрасывать уведомление об устаревании: Deprecated: define(): Declaration of case-insensitive constants is deprecated in ...

The correct casing for this constant is "Foo" Кроме того, при попытке получить доступ к константам, которые были объявлены в режиме без учета регистра (FOO), вы увидете довольно полезное предупреждение: Deprecated: Case-insensitive constants are deprecated.

RFC, обсуждение на Externals.io, реализация

Влияние на обратную совместимость

Крайне маловероятно, что не будет никаких проблем с этим, потому что отловить все варианты использования довольно трудозатратно, но в результате код станет понятней. Вам придется идти в базовый код, туда где объявляются регистро-независимые константы и последовательно исправлять.

Я не нашел на github примеры подобного использования, но как минимум Drupal и WordPress (два довольно старых и зрелых проекта в PHP) имеют регистро-независимые константы.

Опциональный выброс исключений при ошибках в функциях json_encode и json_decode

Все эти годы json_encode() и json_decode() молчали об ошибках в PHP-переменных или json-строках, что приводило к забагованному коду. Одно из моих любимых. Этот случай даже был в знаменитой критике PHP: Фрактал плохого дизайна.

Эта функция абсолютно ненадёжна, если вы конечно не вызываете json_last_error каждый раз при её использовании. json_decode возвращает null для невалидного ввода, при том, что null — абсолютно верный объект для декодируемого JSON'а.

Потребовалось 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. Я настоятельно рекомендую вам начать использовать эту функцию. С появлением этой функции в ядре PHP, вы можете удалить этот пакет и тонны некрасивого шаблонного кода с вызовом json_last_error() в каждом месте где вы работаете с json. 2 и ниже.

RFC, обсуждение на Externals.io, реализация

Влияние на обратную совместимость

Никакого, если вы не используете собственное исключение и/или константу с такими же именами.

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

2 достаточно много устаревших и забагованных функций. В PHP 7. 2. Если вы в PHP 7. В общих правках было предложение проверять получаемую перменную на countable до ее использования в count(). вызываете count() с использованием не-countable переменной, то PHP выведет предупреждение об этом.

Так как при проверке будет использоваться много шаблонного кода, в PHP 7. countable-переменной является массив или объект реализующий \Countable интерфейс. 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 7. PHP использует Perl Compatible Regular Expressions или коротко PCRE в библитеке для работы с регулярными выражениями. 3 уже будет использоваться PCRE2. 2 используется 8.x версия легаси-библиотеки PCRE, а в PHP 7. Обратите внимание, что 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\-.]+/', '');

3, а также и с более старыми версиями. Приведенный выше код отлично отработает не только с PHP 7. Это самая распространенная проблема из всех с которыми можно столкнуться при решении вопросов совместимости. В новом паттерне дефис экранирован - в \-.

Сообщение об ошибке указывает на точное положение символа в регулярном выражении. Это довольно незначительное изменение, но есть шанс, что все пойдет не так. Проверьте ваши регулярные выражения на совместимость с PCRE2 синтаксисом через Regex Buddy или другой подобный софт. Убедитесь, что тщательно проверили свой код. Дополнительные сведения смотрите в описании PCRE2 синтаксиса и устаревшего PCRE синтаксиса.

RFC, обсуждение на Externals.io, реализация

Влияние на обратную совместимость

Исправление варьируется от простого обновления шаблона (например, заэкранировать дефисы) до переписывания шаблонов. Так как PCRE2 более придирчив и строг к шаблонам, некоторые из ваших preg_match() и подобных вызовов могут не работать. Убедитесь, что все ваши тесты проходят.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть