Выпуск №25 — PHP 7.1

Вышел PHP 7.1 — сделаем обзор RFC, вошедших в свежий релиз.

Привет мир!
Вы слушаете «Пятиминутку PHP», выпуск номер 25 — подкаст о новостях из мира PHP, интересных постах в блогах и современных подходах к разработке.

Рад всех поздравить с выходом PHP версии 7.1.0. Давайте сделаем краткий обзор RFC, вошедших в этот релиз.

Напомню, что список всех RFC по уже вышедшим версиям и планирующиеся на будущее можно найти по адресу wiki.php.net/rfc

  • Session ID without hashing
    ID сессии издревна генерировался с помощью специальной хэш-функции. Самое главное в этом процессе — сделать ID сессии непредсказуемым, чтобы посторонний человек не смог его подобрать. Теперь используется функция php_random_bytes() обёрнутая в вызов bin_to_readable().
  • Asynchronous Signal Handling
    В предыдуших версиях PHP сигналы от операционной системы обрабатывались синхронным способом. Была возможность запустить и асинхронную обработку, но это просаживало производительность. Благодаря улучшениями виртуальной машины PHP 7.1 стало возможным обрабатывать сигналы асинхронно без дополнительного overhead’а.
  • Fix inconsistent behavior of $this variable
    Зналили вы, что была возможность переопределить переменную $this тысячью разными способами, например, сделать unset или использовать в качестве переменной для значения в foreach? Теперь все способы испортить $this будут вызывать Fatal Error или Exception Error.
  • Replace «Missing argument» warning with «Too few arguments» exception
    Называние говорит само за себя: если мы забыли передать требуемые аргументы в функцию, то теперь получим Exception (раньше был Warning).
  • Nullable Types
    А что если функция может принимать в качестве аргумента какой-то определённый тип или null? Мы всегда писали в определении функции имя аргумента = null. В PHP 7.1 добавлен новый синтаксис: знак вопроса перед типом. Например, пишем: function foo(?string $x) — аргумент $x может принимать значение типа string или null. Обращу внимание, что новая запись не эквивалентна старой. Если используем новый синтаксис со знаком вопроса, то аргумент от этого не становится не обязательным. Он должен быть явно передан в функцию, даже если мы хотим передать null, иначе получим Exception «too few arguments» из предыдущего RFC. Также этот синтаксис со знаком вопроса позволяет отметить и тип возвращаемого значения, как nullable.
  • Square bracket syntax for array destructuring assignment
    Альтернативный синаксис для конструкции list() о котором я подробно рассказывал в выпуске №21 — теперь вместо list можно использовать квадратные скобки.
  • Warn about invalid strings in arithmetic
    При использовании арифметических операций со строками, которые не являются числами в чистом виде, PHP не выдавал никаких сообщений, а просто конвертировал строки в числа. Например, если сложить «10 яблок» + «5 апельсинов» получим результат 15. В PHP 7.1 такая операция покажет нам предупреждение уровня E_NOTICE или E_WARNING (результат при этом всё равно будет 15).
  • Allow specifying keys in list()
    На этот этот RFC я опять же делал обзор в выпуске №21 — конструкцию list теперь можно использовать не только для разбора пронумерованных массивов, но и для ассоциативных массивов, явно указывая ключи, которые мы хотим извлечь.
  • Iterable
    У нас есть тип array и интерфейс Traversable по которым можно итерироваться с помощью foreach. Но у нас не было возможности определить тип аргумента функции или тип возвращаемого значения, как array или Traversable одновременно, т.е. когда мы заранее не знаем, какой именно тип будет использован. Новый псевдо-тип Iterable покрывает и массивы и Traversable объекты. Вы спросите, что за псевдо-тип такой и как его использовать. Вот вам ближайшая аналогия: вспомните псевдо-тип callable.
  • Generalize support of negative string offsets
    Появилась возможность использовать отрицательное смещение при работе со строками. Например, можно получить второй символ с конца строки, указав для строковой переменной $foo[-2]. Поддержка отрицательного смещения также появляется и в функциях strpos, mb_strpos, file_get_contents и многих других (полный список читайте в RFC по ссылке).
  • Closure from callable function
    Хотите создавать Closure (анонимные функции с захватом контекста) из переменных типа callable просто, в одну строку и быстро в рантайме без рефлексии? Теперь у класса Closure появился публичный статический метод Closure::fromCallable(). В описании к RFC есть пара удачных примеров, посмотрите, чтобы понять зачем это может пригодиться.
  • Deprecate mb_ereg_replace eval option
    Опция e в функциях mb_ereg_replace и mb_eregi_replace объявлена устаревшей (depricated). Эта опция позволяла выполнить eval, что без должного внимания могло привести к проблемам с безопасностью.
  • Deprecate (and remove) Mcrypt
    В PHP 7.1 вызов всех mcrypt_* функций будет показывать предупреждение E_DEPRECATED, а в одной из будущих версий (7.2 или 8.0) планируется вынести эти функции из ядра в отдельное PECL расширение.
  • OpenSSL AEAD support
    В функции openssl_decrypt и openssl_encrypt добавлены параметры для поддержи так называемого режима AEAD (Authenticated Encrypt with Associated Data) — те кто в теме, поймут. Я не в теме.
  • Void Return Type
    Новый тип void для описания возвращаемых результатов. Если мы ненароком вернём из такой функции некое значение (включая null), то получим Fatal Error. При этом сделать просто return (без какого либо значения) для раннего выхода из функции можно — это и будет void. Обратите внимание, что в качестве типа аргументов функции void не применим.
  • Class constant visibility modifiers
    Теперь перед объявлением констант можно указывать модификаторы доступа private, protected и public. Если не указать ничего, то константа считается public, как и в предыдущих версиях.
  • Octal Overflow Protection
    В PHP можно указать значение одного байта используя восьмеричную систему, написав в двойных кавычках обратный слэш (\) и восьмеричное число из трёх цифр. Наример, "\101" — это число 65 в десятичной системе. Однако, чтобы уложиться ровно в 1 байт, максимальная восмеричная форма — это "\377". Предыдущие версии PHP не выводили ошибок при переполнении, т.е. при указании числа большего чем 377. В PHP 7.1 будет выведен Warning.
  • RNG fixes and changes
    Несколько улучшений в функциях работы со случайными числами, которые, внимание, повлекли за собой breaking change: при заданном значении seed, функции mt_rand, rand, array_rand, shuffle, str_shuffle и crypt теперь вернут иное значение, чем в предыдуших версиях. Это может стать причиной трудно понимаемых багов при переходе на 7.1. В моих проектах, в частности, есть один фрагмент, который полагается на заданный seed перед вызовом array_rand.
  • Add HTTP/2 Server Push support to ext/curl
    В PHP 7.0 в расширении curl появилась поддержка нескольких фич из HTTP/2. В PHP 7.1 добавляется ещё одна очень классная функциональность: поддержка HTTP/2 Server Push. Это актуально, если вы используете PHP приложение в качестве клиента и подключаетесь к внешнему ресурсу по HTTP/2.
  • TimeZone::getWindowsID
    В класс IntlTimeZone добавлено два статических метода: getWindowsID() и getIDForWindowsID(). Пример: если вызвать IntlTimeZone::getWindowsID("America/Los_Angeles") то получим "Pacific Standard Time". И наоборот, если вызвать IntlTimeZone::getIDForWindowsID("Pacific TimeZone"), то получим "America/Los_Angeles". Эти методы появились благодаря обновлению библиотеки ICU.
  • Multi catch
    В блоке catch при работе с исключениями можно поймать несколько исключений одновременно, перечислив их типы через вертикальную черту.
  • Forbid dynamic calls to scope introspection functions
    В PHP есть ряд функций, которые меняют или читают переменные из текущей области видимости: extract(), compact(), get_defined_vars(), parse_str(), mb_parse_str(), assert() со строковым аргументом, func_get_args(), func_get_arg() и func_num_args(). Теперь эти функции запрещено вызывать динамически, т.е. с помощью call_user_func() или array_map() и подобными способами. Во-первых, динамический вызов этих функций давал различный результат в разных версиях PHP и в целом такой код был сложен для понимания и зачастую имел неожиданный результат. Во-вторых, динамический вызов этих функций сложно оптимизировать с точки зрения виртуальной машины PHP и это сильно ударяло по производительности. Ещё раз отмечу, что сами функции никуда не исчезают, просто их нужно вызывать явно!
  • Add curl_multi_errno(), curl_share_errno() and curl_share_strerror()
    Расширение curl создаёт ресурс одного из трёх типов: так называемый handle из функции curl_init(), Multi Handle из функции curl_multi_init() и Share Handel из функции curl_share_init(). Чтобы получить ошибку соединения у нас была функция curl_errno(), которая применима для первого типа Handle. Но не было аналогичных функций для Multi Handle и Share Handle. Теперь они появились: curl_multi_errno() и curl_share_errno() — возвращают код ошибки; curl_multi_strerror() и curl_share_strerror() — возвращаю описание ошибки.
  • Throw Error in Extensions
    В PHP 7.0 мы смогли перехватывать стандартные ошибки PHP как исключение Error, но это ещё не работало в расширениях. В PHP 7.1 подтянулись и расширения, такие как Date, DOM, mbstring и другие.
  • More precise float value handling
    Улучшения в точности обработки float значений, что сразу будет заметно при работе с функциями serialize(), json_encode().
  • Additional Context in pcntl_signal Handler
    Добавлен второй аргумент в виде массива к callback функции при использовании pcntl_signal — теперь наш обработчик сигналов получит вторым аргументом дополнительную информацию, контекст.
  • Add session_create_id()
    Добавлиена функция session_create_id(), про котороую лучше прочитать в документации — тонкости работы с сессиями такие тонкие…
  • Add session_gc()
    Добавлена функция session_gc() для принудительного запуска сборщика мусора старых сессий. За подробностями зачем это нужно и в каких случаях применять опять же рекомендую почитать документацию.

Это обновление не такое громкое, как 7.0. Нет информации о серьёзном увеличении производительности, зато подчищены некоторые старые хвосты, добавлено немного синтаксического сахара, в целом годный инкрементальный релиз. Обновляемся по плану!