PHP 7: Что нового. часть 2
Категория: / DEV Блог
/ PHP (LAMP)
PHP 7: Что нового. Часть 1.
Криптографически стойкий генератор псевдослучайных чисел (англ. Cryptographically secure pseudorandom number generator, CSPRNG)
Новведение добавляет две новых функции для генерации криптографически стойких целых чисел и строк.
Функции работают одинаково на всех платформах.
Обе функции сгенерируют исключение `Error`, если источник необходимой случайности будет не найден.
Необратимые изменения
зарезервированные имена `random_int`, `random_bytes`.
Easy User-land CSPRNG
В php 5.6 появилась возможность испльзовать массивы в константах (const),
теперь эта возможность добралась и до define.
В PHP7 добавились два новых класса рефлексии.
Первый `ReflectionGenerator`, используется для интроспекции генераторов:
Второй `ReflectionType` для лучшей работы со скалярными и возвращяемыми типами:
Также, класс `ReflectionParameter` обзавелся двумя новыми методами:
Новые методы в `ReflectionFunctionAbstract`:
Необратимые изменения
Зарезервированные имена `ReflectionGenerator`, `ReflectionType`.
Теперь программист может использовать глобальные ключевые слова в названиях
свойств, констант, методов в классах,интерфейсах и трейтах.
Т.е. если раньше название метода зарезерварованным словом (new/for/etc...) приводило к ошибке, теперь это разрешено:
Единственным ограничением остается слово `class`, оно не может быть использовано в названии константы,
иначе возникает конфликт с `ClassName::class`.
Context Sensitive Lexer
Одно из основных изменений!
Теперь обращения к сложносочиненным переменным разбираются последовательно СЛЕВА НАПРАВО.
Новый разбор вложенности переменных более интуитивен
Необратимые изменения
Старый код написанный с использованием {} для обработки переменных возможно не будет работать в новой версии PHP7.
Uniform Variable Syntax
Ранее движок PHP не позволял перехватывать фатальные ошибки, теперь эти ошибки преобразованы в исключения,
которые пользователь может обработать. И что не менее важно, конструкции finally и деструкторы объектов будут гарантированно вызваны в случае фатальных ошибок.
Дополнительным преимуществом новой системы обработки ошибок являтеся возможность получить стек вызовов (stack traces) во время ошибки.
Иерархия исключений
Необратимые изменения
- Кастомные обработчики ошибок для recoverable fatal ошибок больше не будут работать
- Ошибки разбора в `eval()`-коде теперь генерируют исключения, которые нужно ловить в `try...catch`
Exceptions in the Engine
Теперь класс Exception следует контракту Throwable,
эта унификация нужна для работы выражений catch-all (`catch (Exception $e)`) в легаси-скриптах, когда фатальные ошибки не являлись исключениями.
`Exception` и `Error` следуют интерфейсу `Throwable`
`Throwable` не может быть использован в пользовательских классах, программист как и раньше должен наследоваться от существующих классов исключений.
Throwable Interface
Поменялась семантика работы с целыми чилами для обеспечения кроссплатформенности:
- Кастинг `NAN` и `INF` в integer всегда = 0
- Битовый сдвиг `<<, >>` на отрицательное число теперь запрещена (возврат false, с ошибкой E_WARNING)
- << левый сдвиг с количством бит превышающем размер целого всегда = 0
- >> правый сдвиг с количством бит превышающем размер целого = 0 или -1 (зависит от знака)
Необратимые изменения
Код полагающийся на старые семантические правила не будет работать
Integer Semantics
Из-за проблем с лицензированием старого расширения JSON, которое создавало проблемы для линуксойдов, решено заменить расширение на JSOND.
В новой библиотеке присутствует выигрыш в производительности и, что печально, обратно несовместимые изменения.
Необратимые изменения
- Число не должно заканчиваться точкой "." (`34.` должно быть `34.0` или `34`)
- Экспонента `e` не должна следовать сразу за точкой (`3.e3` должно быть `3.0e3` или просто `3e3`)
Replace current json extension with jsond
При передаче float параметра в функцию, которая ожидает integer, может произойти обрезание параметра до размеров integer. Это может повлечь за собой трудно выявляемые баги. Поэтому при ошибочном конвертировании float в integer будет возвращен null и сгенерирована ошибка E_WARNING.
Необратимые изменения
Старый код, который раньше работал теперь будет генерировать E_WARNING и может перестать работать, если
результат вызова функции напрямую передается в другую функцию (т.к. будет передаваться `null`).
ZPP Failure on Overflow
Цикл foreach имеет несколько неприятных особенностей когда работает с копиями и ссылками на массив;
нерабочие манипуляторы указателя массива current(), reset(); изменение массива, по которому проходит итерация..
Подробнее про foreach читать тут
Fix "foreach" behavior
В документации list() сказано, что оператор не поддерживает строки, одно рассмотрим ситуацию
Теперь такую возможность закрыли и list() со строками запрещен совсем.
Также, вызов list() с пустым аргументом вызовет фатальную ошибку;
порядок присвоения переменных изменился с лево-направо:
Необратимые изменения
list() не распаковывает строки!
Вызов list() без параметров ведет к ошибке
Изменен порядок распаковки, в некоторых случаях может возвращаться null
Fix list() behavior inconsistency[/off]
До PHP7, когда делитель был 0 для операторов деления / или модуля %, возвращалась ложь (false) и генерировалось предупреждение E_WARNING.
Это явный бред для математической операции возвращать булево значение, поэтому такое поведение поправили.
Теперь оператор деления возвращает float равный INF, -INF, или NAN.
Оператор остатка больше не выдает E_WARNING, а бросает исключение DivisionByZeroError (intdiv() делает также).
Кстати, intdiv() также выкидывает исключение ArithmeticError, когда в результате слечается переполнение integer.
Необратимые изменения
Оператор деления больше не возвращает `false`
Оператор остатка от деления (модуль) бросает исключение при делении на 0 вместо возврата false
При реализации своего обработчика сессий, функции `SessionHandlerInterface` которые ждут возврата `true` или `false` не работают как положено.
Ошибка приводила к тому, что только -1 трактовалась как false, а реальный false выдавался за истину..
Теперь этот код упадет с фатальной ошибкой.
Необратимые изменения
- boolean false воспринимается как false. false, -1 вызовут фатальную ошибку
- Любое другое значение помимо boolean, `0`, или `-1` будет неудачно и вызовет предупреждение
Fix handling of custom session handler return values[/off]
Конструкторы вида className::className() больше не используются, остался только __construct().
Если не установлена временная зона date.timezone в файле конфигурации, php выдавал предупреждение. Теперь зона по-умолчанию принимается за UTC и ошибки не возникает.
Раритеты <% (<%=), %>, <script language="php">, и </script> окончательно выпилены
Раньше можно было указать несколько меток default в операторе switch (исполнялась только последняя),
Теперь данное поведение вызовет фатальную ошибку.
Фатальную ошибку вызовет использование в фукнции аргументов и одинаковыми названиями.
Следующие модули удалены из ядра (доступны в PECL):
- sapi/aolserver
- sapi/apache
- sapi/apache_hooks
- sapi/apache2filter
- sapi/caudium
- sapi/continuity
- sapi/isapi
- sapi/milter
- sapi/nsapi
- sapi/phttpd
- sapi/pi3web
- sapi/roxen
- sapi/thttpd
- sapi/tux
- sapi/webjames
- ext/mssql
- ext/mysql
- ext/sybase_ct
- ext/ereg
Removal of dead or not yet PHP7 ported SAPIs and extensions
Удалена поддержка преобразований строк содержащих шестнадцатеричные числа.
Вместо простого кастига, строковые hex-числа должны валидироваться и конвертироваться в целое число с помощью функции filter_var():
Необратимые изменения
Новое поведение поломает функцию is_numeric() и операторы `==`, `+`, `-`, `*`, `/`, `%`, `**`, `++`, and `--`
Remove hex support in numeric strings
- mysql extension (ext/mysql)
- ereg extension (ext/ereg)
- присвоение &new по ссылке
- вызов нестатических методов из вне Class::method(), где method() - нестатический метод
Необратимые изменения
Код с предупреждениями об устаревании (deprecation warning) в PHP 5 больше не будет работать (предупреждали же!)
Remove deprecated functionality in PHP 7
Предупреждения категории E_STRICT удалены из PHP, или переквалифицированны в E_DEPRECATED / E_NOTICE / E_WARNING.
Необратимые изменения
Так как E_STRICT низший уровень ошибок, любое повышение ошибки до E_WARNING может поломать кастомные обработчики ошибок
Reclassify E_STRICT notices
С появлением нового API хэширования паролей в PHP5.5, многие стали использовать его и генерировать свои собственные "соли". К сожалению программисты зачастую используют криптографически не безопасные функции типа mt_rand(), делая свою "соль" слишком слабой, по отношению к сгенерированной по-умолчанию. В общем, пользователям запретили использовать несекьюрные соли.
Неправильные восьмеричные литералы теперь генерируют ошибку парсинга, а не проглатываются как раньше.
substr() теперь возвращает пустую строку вместо false, когда начальная позиция подстроки совпадает с длиной строки.
В остальных случаях substr() может попрежнему возвращать false
Он утонул. В PHP6 планировали внедрить полную поддержку юникода в ядро, но эта затея оказалась слишком неподъемной, объем работ слишком велик.
Когда ребята это поняли, решено было пропустить мажорную версию (6), чтобы PHP не ассоциировался с фейлом, так началась работа над PHP7,
в который вошли многие наработки нерожденного.
Name of Next Release of PHP
PHP7 Что нового - первая часть
@Ссылки
Оригинал статьи
Миграция с PHP5.X -> PHP7
Онлайн выполнение PHP кода для тестирования всех версий PHP
Функции CSPRNG
Криптографически стойкий генератор псевдослучайных чисел (англ. Cryptographically secure pseudorandom number generator, CSPRNG)
Новведение добавляет две новых функции для генерации криптографически стойких целых чисел и строк.
Функции работают одинаково на всех платформах.
string random_bytes(int length);
int random_int(int min, int max);
Обе функции сгенерируют исключение `Error`, если источник необходимой случайности будет не найден.
Необратимые изменения
зарезервированные имена `random_int`, `random_bytes`.
Easy User-land CSPRNG
Поддержка массивов в объявлениях define
В php 5.6 появилась возможность испльзовать массивы в константах (const),
теперь эта возможность добралась и до define.
define('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']);
Доработка Reflection
В PHP7 добавились два новых класса рефлексии.
Первый `ReflectionGenerator`, используется для интроспекции генераторов:
class ReflectionGenerator
{
public __construct(Generator $gen)
public array getTrace($options = DEBUG_BACKTRACE_PROVIDE_OBJECT)
public int getExecutingLine(void)
public string getExecutingFile(void)
public ReflectionFunctionAbstract getFunction(void)
public Object getThis(void)
public Generator getExecutingGenerator(void)
}
Второй `ReflectionType` для лучшей работы со скалярными и возвращяемыми типами:
class ReflectionType
{
public bool allowsNull(void)
public bool isBuiltin(void)
public string __toString(void)
}
Также, класс `ReflectionParameter` обзавелся двумя новыми методами:
class ReflectionParameter
{
// ...
public bool hasType(void)
public ReflectionType getType(void)
}
Новые методы в `ReflectionFunctionAbstract`:
class ReflectionFunctionAbstract
{
// ...
public bool hasReturnType(void)
public ReflectionType getReturnType(void)
}
Необратимые изменения
Зарезервированные имена `ReflectionGenerator`, `ReflectionType`.
Изменения с PHP 5.x
Новые правила использования зарезервированных ключевых слов
Теперь программист может использовать глобальные ключевые слова в названиях
свойств, констант, методов в классах,интерфейсах и трейтах.
Т.е. если раньше название метода зарезерварованным словом (new/for/etc...) приводило к ошибке, теперь это разрешено:
Project::new('Project Name')->private()->for('purpose here')->with('username here');
Единственным ограничением остается слово `class`, оно не может быть использовано в названии константы,
иначе возникает конфликт с `ClassName::class`.
Context Sensitive Lexer
Унифицированный синтаксис переменных
Одно из основных изменений!
Теперь обращения к сложносочиненным переменным разбираются последовательно СЛЕВА НАПРАВО.
// вложенность ::
$foo::$bar::$baz // доступ к свойству $baz свойства $foo::$bar
// вложенность ()
foo()() // вызываем() результат вызова foo()
// операторы над выражениями заключенными в ()
(function () {})() // IIFE синтаксис JS
Новый разбор вложенности переменных более интуитивен
// old meaning // new meaning
$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()
Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()
Необратимые изменения
Старый код написанный с использованием {} для обработки переменных возможно не будет работать в новой версии PHP7.
Uniform Variable Syntax
Исключения в движке
Ранее движок PHP не позволял перехватывать фатальные ошибки, теперь эти ошибки преобразованы в исключения,
которые пользователь может обработать. И что не менее важно, конструкции finally и деструкторы объектов будут гарантированно вызваны в случае фатальных ошибок.
Дополнительным преимуществом новой системы обработки ошибок являтеся возможность получить стек вызовов (stack traces) во время ошибки.
function sum(float ...$numbers) : float
{
return array_sum($numbers);
}
try {
$total = sum(3, 4, null);
} catch (TypeError $typeErr) {
// ошибки несоответствия типа
}
Иерархия исключений
interface Throwable
|- Exception implements Throwable
|- ...
|- Error implements Throwable
|- TypeError extends Error
|- ParseError extends Error
|- AssertionError extends Error
|- ArithmeticError extends Error
|- DivisionByZeroError extends ArithmeticError
Необратимые изменения
- Кастомные обработчики ошибок для recoverable fatal ошибок больше не будут работать
- Ошибки разбора в `eval()`-коде теперь генерируют исключения, которые нужно ловить в `try...catch`
Exceptions in the Engine
Интерфейс Throwable
Теперь класс Exception следует контракту Throwable,
эта унификация нужна для работы выражений catch-all (`catch (Exception $e)`) в легаси-скриптах, когда фатальные ошибки не являлись исключениями.
interface Throwable
|- Exception implements Throwable
|- ...
|- Error implements Throwable
|- TypeError extends Error
|- ParseError extends Error
|- AssertionError extends Error
|- ArithmeticError extends Error
|- DivisionByZeroError extends ArithmeticError
`Exception` и `Error` следуют интерфейсу `Throwable`
interface Throwable
{
final public string getMessage ( void )
final public mixed getCode ( void )
final public string getFile ( void )
final public int getLine ( void )
final public array getTrace ( void )
final public string getTraceAsString ( void )
public string __toString ( void )
}
`Throwable` не может быть использован в пользовательских классах, программист как и раньше должен наследоваться от существующих классов исключений.
Throwable Interface
Целочисленная семантика
Поменялась семантика работы с целыми чилами для обеспечения кроссплатформенности:
- Кастинг `NAN` и `INF` в integer всегда = 0
- Битовый сдвиг `<<, >>` на отрицательное число теперь запрещена (возврат false, с ошибкой E_WARNING)
- << левый сдвиг с количством бит превышающем размер целого всегда = 0
- >> правый сдвиг с количством бит превышающем размер целого = 0 или -1 (зависит от знака)
Необратимые изменения
Код полагающийся на старые семантические правила не будет работать
Integer Semantics
Расширение JSON Extension заменено на JSOND
Из-за проблем с лицензированием старого расширения JSON, которое создавало проблемы для линуксойдов, решено заменить расширение на JSOND.
В новой библиотеке присутствует выигрыш в производительности и, что печально, обратно несовместимые изменения.
Необратимые изменения
- Число не должно заканчиваться точкой "." (`34.` должно быть `34.0` или `34`)
- Экспонента `e` не должна следовать сразу за точкой (`3.e3` должно быть `3.0e3` или просто `3e3`)
Replace current json extension with jsond
ZPP ошибка при переполнении
ZPP: zend_parse_parametersПри передаче float параметра в функцию, которая ожидает integer, может произойти обрезание параметра до размеров integer. Это может повлечь за собой трудно выявляемые баги. Поэтому при ошибочном конвертировании float в integer будет возвращен null и сгенерирована ошибка E_WARNING.
Необратимые изменения
Старый код, который раньше работал теперь будет генерировать E_WARNING и может перестать работать, если
результат вызова функции напрямую передается в другую функцию (т.к. будет передаваться `null`).
ZPP Failure on Overflow
Доработки foreach()
Цикл foreach имеет несколько неприятных особенностей когда работает с копиями и ссылками на массив;
нерабочие манипуляторы указателя массива current(), reset(); изменение массива, по которому проходит итерация..
Подробнее про foreach читать тут
Fix "foreach" behavior
Изменение поведения list()
В документации list() сказано, что оператор не поддерживает строки, одно рассмотрим ситуацию
// разыменовывание массива
$str[0] = 'ab';
list($a, $b) = $str[0];
echo $a; // a
echo $b; // b
// разыменовывание объекта
$obj = new StdClass();
$obj->prop = 'ab';
list($a, $b) = $obj->prop;
echo $a; // a
echo $b; // b
// возврат функции
function func()
{
return 'ab';
}
list($a, $b) = func();
var_dump($a, $b);
echo $a; // a
echo $b; // b
Теперь такую возможность закрыли и list() со строками запрещен совсем.
Также, вызов list() с пустым аргументом вызовет фатальную ошибку;
порядок присвоения переменных изменился с лево-направо:
$a = [1, 2];
list($a, $b) = $a;
// БЫЛО: $a = 1, $b = 2
// СТАЛО: $a = 1, $b = null + "Undefined index 1"
$b = [1, 2];
list($a, $b) = $b;
// БЫЛО: $a = null + "Undefined index 0", $b = 2
// СТАЛО: $a = 1, $b = 2
Необратимые изменения
list() не распаковывает строки!
Вызов list() без параметров ведет к ошибке
Изменен порядок распаковки, в некоторых случаях может возвращаться null
Fix list() behavior inconsistency[/off]
Изменения в семантике деления на 0
До PHP7, когда делитель был 0 для операторов деления / или модуля %, возвращалась ложь (false) и генерировалось предупреждение E_WARNING.
Это явный бред для математической операции возвращать булево значение, поэтому такое поведение поправили.
Теперь оператор деления возвращает float равный INF, -INF, или NAN.
Оператор остатка больше не выдает E_WARNING, а бросает исключение DivisionByZeroError (intdiv() делает также).
Кстати, intdiv() также выкидывает исключение ArithmeticError, когда в результате слечается переполнение integer.
var_dump(3/0); // float(INF) + E_WARNING
var_dump(0/0); // float(NAN) + E_WARNING
var_dump(0%0); // DivisionByZeroError
intdiv(PHP_INT_MIN, -1); // ArithmeticError
Необратимые изменения
Оператор деления больше не возвращает `false`
Оператор остатка от деления (модуль) бросает исключение при делении на 0 вместо возврата false
Исправления в возвращаемых значениях кастомных обработчиках сессий
При реализации своего обработчика сессий, функции `SessionHandlerInterface` которые ждут возврата `true` или `false` не работают как положено.
Ошибка приводила к тому, что только -1 трактовалась как false, а реальный false выдавался за истину..
class FileSessionHandler implements SessionHandlerInterface
{
private $savePath;
function open($savePath, $sessionName)
{
return false; // always fail
}
function close(){return true;}
function read($id){}
function write($id, $data){}
function destroy($id){}
function gc($maxlifetime){}
}
session_set_save_handler(new FileSessionHandler());
session_start(); // до PHP 7 ошибка не возникала
Теперь этот код упадет с фатальной ошибкой.
Необратимые изменения
- boolean false воспринимается как false. false, -1 вызовут фатальную ошибку
- Любое другое значение помимо boolean, `0`, или `-1` будет неудачно и вызовет предупреждение
Fix handling of custom session handler return values[/off]
Конструкторы в стиле PHP4 устарели
Конструкторы вида className::className() больше не используются, остался только __construct().
Удалено предупреждение date.timezone
Если не установлена временная зона date.timezone в файле конфигурации, php выдавал предупреждение. Теперь зона по-умолчанию принимается за UTC и ошибки не возникает.
Альтернативные PHP тэги удалены
Раритеты <% (<%=), %>, <script language="php">, и </script> окончательно выпилены
Множественный default блок в Switch-e
Раньше можно было указать несколько меток default в операторе switch (исполнялась только последняя),
Теперь данное поведение вызовет фатальную ошибку.
Одинаковые названия аргументов фукнции
Фатальную ошибку вызовет использование в фукнции аргументов и одинаковыми названиями.
function foo($version, $version)
{
return $version;
}
echo foo(5, 7);
// до PHP 7
7
// PHP 7+
Fatal error: Redefinition of parameter $version in /redefinition-of-parameters.php
Удаленные SAPI
Следующие модули удалены из ядра (доступны в PECL):
- sapi/aolserver
- sapi/apache
- sapi/apache_hooks
- sapi/apache2filter
- sapi/caudium
- sapi/continuity
- sapi/isapi
- sapi/milter
- sapi/nsapi
- sapi/phttpd
- sapi/pi3web
- sapi/roxen
- sapi/thttpd
- sapi/tux
- sapi/webjames
- ext/mssql
- ext/mysql
- ext/sybase_ct
- ext/ereg
Removal of dead or not yet PHP7 ported SAPIs and extensions
HEX-числа в строках
Удалена поддержка преобразований строк содержащих шестнадцатеричные числа.
var_dump(is_numeric('0x123'));
var_dump('0x123' == '291');
echo '0x123' + '0x123';
// до PHP 7
bool(true)
bool(true)
582
// PHP 7+
bool(false)
bool(false)
0
var_dump((int) '0x123'); // int(0)
Вместо простого кастига, строковые hex-числа должны валидироваться и конвертироваться в целое число с помощью функции filter_var():
var_dump(filter_var('0x123', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX)); // int(291)
Необратимые изменения
Новое поведение поломает функцию is_numeric() и операторы `==`, `+`, `-`, `*`, `/`, `%`, `**`, `++`, and `--`
Remove hex support in numeric strings
Удаление старого функционала
- mysql extension (ext/mysql)
- ereg extension (ext/ereg)
- присвоение &new по ссылке
- вызов нестатических методов из вне Class::method(), где method() - нестатический метод
Необратимые изменения
Код с предупреждениями об устаревании (deprecation warning) в PHP 5 больше не будет работать (предупреждали же!)
Remove deprecated functionality in PHP 7
Переклассифицирование и удаление сообщений E_STRICT
Предупреждения категории E_STRICT удалены из PHP, или переквалифицированны в E_DEPRECATED / E_NOTICE / E_WARNING.
Необратимые изменения
Так как E_STRICT низший уровень ошибок, любое повышение ошибки до E_WARNING может поломать кастомные обработчики ошибок
Reclassify E_STRICT notices
Устаревание опции Salt функции password_hash()
С появлением нового API хэширования паролей в PHP5.5, многие стали использовать его и генерировать свои собственные "соли". К сожалению программисты зачастую используют криптографически не безопасные функции типа mt_rand(), делая свою "соль" слишком слабой, по отношению к сгенерированной по-умолчанию. В общем, пользователям запретили использовать несекьюрные соли.
Ошибки восьмеричных литералов
Неправильные восьмеричные литералы теперь генерируют ошибку парсинга, а не проглатываются как раньше.
echo 0678; // Parse error: Invalid numeric literal in...
substr() изменение возвращаемого значения
substr() теперь возвращает пустую строку вместо false, когда начальная позиция подстроки совпадает с длиной строки.
var_dump(substr('a', 1));
// до PHP 7
bool(false)
// PHP 7+
string(0) ""
В остальных случаях substr() может попрежнему возвращать false
Что там с PHP6
Он утонул. В PHP6 планировали внедрить полную поддержку юникода в ядро, но эта затея оказалась слишком неподъемной, объем работ слишком велик.
Когда ребята это поняли, решено было пропустить мажорную версию (6), чтобы PHP не ассоциировался с фейлом, так началась работа над PHP7,
в который вошли многие наработки нерожденного.
Name of Next Release of PHP
PHP7 Что нового - первая часть
@Ссылки
Оригинал статьи
Миграция с PHP5.X -> PHP7
Онлайн выполнение PHP кода для тестирования всех версий PHP
ага)
и как, успешно магрировал?