PHP 8.4.6 Released!

Изменения, которые ломают обратную совместимость

Изменения в обработке ошибок и исключений

В PHP 7 многие фатальные и поправимые фатальные ошибки переделали в исключения. Эти исключения наследуют класс Error, который, в свою очередь, реализует интерфейс Throwable (новый базовый интерфейс, который наследуют исключения).

Поэтому пользовательские обработчики ошибок не вызовутся, если вместо вызова ошибки выбросится исключение (порождая новые фатальные ошибки из-за неперехваченных исключений класса Error).

Более подробное описание работы ошибок в PHP 7 даёт страница ошибки PHP 7. Это руководство только перечисляет изменения, которые приводят к обратной несовместимости.

Функция set_exception_handler() больше не гарантирует получение объекта класса Exception

Код, который реализует регистрацию обработчика исключений функцией set_exception_handler() через декларацию типа Exception вызовет фатальную ошибку, если выбросится исключение Error.

Потребуется убрать объявление класса из обработчика, если требуется работа обработчика в PHP 5 и 7. Достаточно изменить тип Exception на тип Throwable, если код планируется использовать только в PHP 7.

<?php

// Только PHP 5. В PHP 7 при исключении другого типа вызывает фатальную ошибку
function handler(Exception $e) { /* ... */ }
set_exception_handler('handler');

// Будет работать PHP 5 и 7
function handler($e) { /* ... */ }

// Только PHP 7
function handler(Throwable $e) { /* ... */ }

?>

Встроенные конструкторы вызывают исключения при ошибке

Раньше отдельные внутренние классы возвращали null или бесполезный объект, когда конструктор терпел неудачу. Теперь встроенные классы в таких случаях выбрасывают исключение Exception, так же, как это уже делают пользовательские классы.

Ошибки разбора бросают исключение класса ParseError

Ошибки разбора бросают исключение класса ParseError. Обработка ошибок eval() должна включать в себя блок catch, который будет ловить эту ошибку.

Изменение строгости уведомлений E_STRICT

Сообщения уровня E_STRICT переквалифицировали по другим уровням. Константу E_STRICT сохранили, поэтому установка error_reporting(E_ALL|E_STRICT) не вызовет ошибок.

Изменение строгости сообщений E_STRICT
Ситуация Новый уровень или поведение
Установка ресурса как индекса E_NOTICE
Абстрактные статические методы Сообщение убрали, ошибка не возникает
«Переопределение» конструктора Сообщение убрали, ошибка не возникает
Несоблюдение сигнатуры при наследовании E_WARNING
Одинаковые (совместимые) свойства в двух разных трейтах Сообщение убрали, ошибка не возникает
Нестатический доступ к статическому свойству E_NOTICE
Только переменные присваиваются по ссылке E_NOTICE
Только переменные передаются по ссылке E_NOTICE
Вызов нестатического метода статически E_DEPRECATED

Изменения в обработке переменных

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

Изменения в обработке непрямых переменных, свойств и методов

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

Старая и новая оценка непрямых выражений
Выражение Интерпретация PHP 5 Интерпретация PHP 7
$$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']()

Код, использующий старый порядок раскрытия справа-налево, должен быть переписан с использованием фигурных скобок (смотрите средний столбец в таблице выше). Это сделает код рабочим как в PHP 5.x, так и в PHP 7.x.

Также это относится и к ключевому слову global. Для эмуляции старого поведения необходимо использовать фигурные скобки:

<?php
function f() {
// Корректно только в PHP 5.
global $$foo->bar;

// Корректно в PHP 5 и 7.
global ${$foo->bar};
}
?>

Изменение в обработке list()

list() больше не присваивает переменные в обратном порядке

Теперь list() присваивает переменные в том порядке, как они перечислены, а не в обратном. В целом, это влияет только на случаи, когда list() используется совместно с оператором массива [], как показано ниже:

<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>

Результат выполнения приведённого примера в PHP 5:

array(3) {
  [0]=>
  int(3)
  [1]=>
  int(2)
  [2]=>
  int(1)
}

Результат выполнения приведённого примера в PHP 7:

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

Также хочется отметить, что полагаться на порядок присвоения оператором list() - не самое разумное решение, поскольку он снова может поменяться в будущем.

Пустое присвоение list() больше не разрешено

Конструкция list() больше не может быть пустой. Следующие примеры недопустимы:

<?php
list() = $a;
list(,,) =
$a;
list(
$x, list(), $y) = $a;
?>
list() не может раскрывать строки

list() более не может раскрывать строки. Используйте str_split().

Изменён порядок массива при автоматическом создании через присвоение по ссылке

Порядок создания элементов в массиве был изменён, когда элемент создаётся путём присвоения значения переменной, на которую ссылается этот элемент. Пример:

<?php
$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

Результат выполнения приведённого примера в PHP 5:

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

Результат выполнения приведённого примера в PHP 7:

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

Скобки вокруг аргументов функции больше ни на что не влияют

В PHP 5 при использовании избыточных скобок вокруг аргументов функции не выводилось предупреждение, когда аргумент передавался по ссылке. Теперь предупреждение выводится всегда.

<?php
function getArray() {
return [
1, 2, 3];
}

function
squareArray(array &$a) {
foreach (
$a as &$v) {
$v **= 2;
}
}

// Выведет предупреждение в PHP 7.
squareArray((getArray()));
?>

Результат выполнения приведённого примера:

Notice: Only variables should be passed by reference in /tmp/test.php on line 13

Изменения foreach

Небольшие изменения были внесены в поведение управляющей структуры foreach. Основное изменение касается модификации итерируемого массива и обработки его внутреннего указателя.

foreach больше не изменяет внутренний указатель массива

До PHP 7 в процессе итерации массива в foreach, его внутренний указатель изменялся. В примере ниже показано, что это поведение изменено:

<?php
$array
= [0, 1, 2];
foreach (
$array as &$val) {
var_dump(current($array));
}
?>

Результат выполнения приведённого примера в PHP 5:

int(1)
int(2)
bool(false)

Результат выполнения приведённого примера в PHP 7:

int(0)
int(0)
int(0)

foreach по значениям оперирует копией массива

Если foreach используется для стандартного перебора по значению, то он оперирует копией массива, а не самим массивом. Это значит, что изменения внесённые в массив внутри цикла не затронут перебираемые значения.

Для foreach по ссылке улучшили поведение при итерации

Когда foreach используется для перебора по ссылке, он будет лучше отслеживать изменения, вносимые в массив в процессе итерации. К примеру, добавление элементов к итерируемому массиву приведёт к тому, что эти новые элементы попадут в перебор:

<?php
$array
= [0];
foreach (
$array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>

Результат выполнения приведённого примера в PHP 5:

int(0)

Результат выполнения приведённого примера в PHP 7:

int(0)
int(1)

Итерация объектов не реализующих Traversable

Итерация объектов не реализующих Traversable теперь происходит так же, как и итерация массива по ссылке. Так получается вследствие того, что улучшения поведения при изменении массива во время итерации также влияет при добавлении или удалении свойств объекта.

Изменение в обработке значений типа int

Некорректная восьмеричная нотация

Ранее восьмеричные литералы, содержащие некорректные числа молча обрезались (0128 считались за 012). Сейчас в таких случаях будет выдана ошибка разбора.

Отрицательные побитовые смещения

Теперь побитовые смещения на отрицательную величину будут бросать исключение ArithmeticError:

<?php
var_dump
(1 >> -1);
?>

Результат выполнения приведённого примера в PHP 5:

int(0)

Результат выполнения приведённого примера в PHP 7:

Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2
Stack trace:
#0 {main}
  thrown in /tmp/test.php on line 2

Побитовые смещения с выходом из допустимого диапазона

Побитовые смещения (в обоих направлениях) за пределы ширины типа int будут всегда возвращать 0. Раньше поведение зависело от архитектуры.

Изменение в делении на ноль

Ранее использование нуля в качестве делителя в операциях деления (/) или деления по модулю (%) приводило к ошибке уровня E_WARNING и возврату значения false. Теперь оператор деления возвращает число с плавающей точкой, равное +INF, -INF или NAN, как определено в IEEE 754. Деление по модулю вместо ошибки уровня E_WARNING будет выбрасывать исключение DivisionByZeroError.

<?php
var_dump
(3/0);
var_dump(0/0);
var_dump(0%0);
?>

Результат выполнения приведённого примера в PHP 5:

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

Результат выполнения приведённого примера в PHP 7:

Warning: Division by zero in %s on line %d
float(INF)

Warning: Division by zero in %s on line %d
float(NAN)

PHP Fatal error:  Uncaught DivisionByZeroError: Modulo by zero in %s line %d

Изменения в обработке строк

Шестнадцатеричные строки больше не считаются за числовые

Строки, содержащие шестнадцатеричные символы больше не считаются за числовые. Пример:

<?php
var_dump
("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>

Результат выполнения приведённого примера в PHP 5:

bool(true)
bool(true)
int(15)
string(2) "oo"

Результат выполнения приведённого примера в PHP 7:

bool(false)
bool(false)
int(0)

Notice: A non well formed numeric value encountered in /tmp/test.php on line 5
string(3) "foo"

Используйте функцию filter_var() для проверки строки на содержание шестнадцатеричного числа и преобразования этой строки к значению типа int:

<?php
$str
= "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (
false === $int) {
throw new
Exception("Некорректное целое число!");
}
var_dump($int); // int(65535)
?>

\u{ может вызывать ошибки

В связи с добавлением нового синтаксиса экранирования кодов Unicode, строки, содержащие строку \u{, предваряющую некорректную последовательность, может привести к фатальной ошибке. Для того, чтобы этого избежать, необходимо экранировать первый обратный слеш.

Удалённые функции

Функции call_user_method() и call_user_method_array()

Эти функции устарели в PHP 4.1.0 в пользу функций call_user_func() и call_user_func_array(). Обратите внимание на функции переменных и (или) оператор ....

Семейство функций ereg*

Функции ereg удалили. Рекомендованная альтернатива — Perl-совместимые регулярные выражения PCRE.

Псевдонимы модуля mcrypt

Устаревшую функцию mcrypt_generic_end() удалили в пользу функции mcrypt_generic_deinit().

Кроме этого, устаревшие функции mcrypt_ecb(), mcrypt_cbc(), mcrypt_cfb() и mcrypt_ofb() удалили в пользу функции mcrypt_decrypt() с соответствующей константой MCRYPT_MODE_*.

Функции модуля mysql

Все функции модуля ext/mysql удалили. Подробнее о выборе другого API-интерфейса к СУБД MySQL рассказывает раздел «Выбор MySQL API».

Функции модуля mssql

Все функции модуля ext/mssql удалили.

Псевдонимы модуля intl

Устаревшие псевдонимы datefmt_set_timezone_id() и IntlDateFormatter::setTimeZoneID() удалили в пользу функции datefmt_set_timezone() и метода IntlDateFormatter::setTimeZone().

set_magic_quotes_runtime()

Функцию set_magic_quotes_runtime() и её псевдоним magic_quotes_runtime() удалили. Функции объявили устаревшими в PHP 5.3.0, поскольку они потеряли смысл с отказом от магических кавычек в PHP 5.4.0.

set_socket_blocking()

Устаревший псевдоним set_socket_blocking() удалили в пользу функции stream_set_blocking().

Функция dl() в менеджере процессов PHP-FPM

Функцию dl() больше нельзя использовать в PHP-FPM. Однако функцию оставили в CLI-интерфейсе и встроенных интерфейсах SAPI.

Функции модуля GD Type1

Поддержку шрифтов PostScript Type1 удалили из модуля GD. Соответственно удалили следующие функции:

  • imagepsbbox()
  • imagepsencodefont()
  • imagepsextendfont()
  • imagepsfreefont()
  • imagepsloadfont()
  • imagepsslantfont()
  • imagepstext()

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

Удалённые директивы INI-файла

Удалённые возможности

Следующие INI-директивы были удалены, так как связанные с ними функции также были удалены:

  • always_populate_raw_post_data
  • asp_tags

xsl.security_prefs

Директива xsl.security_prefs была удалена. Вместо неё для контроля настроек безопасности должен вызываться метод XsltProcessor::setSecurityPrefs() на уровне каждого процессора.

Прочие изменения, которые затрагивают обратную совместимость

Новые объекты нельзя присваивать по ссылке

Результат оператора new больше нельзя присваивать переменной по ссылке:

<?php

class C {}
$c =& new C;

?>

Результат выполнения приведённого примера в PHP 5:

Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3

Результат выполнения приведённого примера в PHP 7:

Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3

Некорректные имена классов, интерфейсов и трейтов

Следующие имена нельзя использовать для классов, интерфейсов и трейтов:

Дополнительно к предыдущим именам, следующие имена тоже нельзя использовать. Следующие имена не вызовут ошибку в PHP 7.0, но их зарезервировали на будущее, а от разработчиков требуют считать их устаревшими.

Удалили PHP-теги ASP и script

Удалили поддержку тегов ASP и script для определения PHP-кода.

Удалённые теги ASP и script
Открывающий тег Закрывающий тег
<% %>
<%= %>
<script language="php"> </script>

Удалили вызовы из неподходящего контекста

Статические вызовы нестатических методов из неподходящего контекста, которые признали устаревшими в PHP 5.6 , теперь оставят переменную $this неопределённой для вызываемого метода и выведут предупреждение.

<?php

class A
{
public function
test()
{
var_dump($this);
}
}

// Обратите внимание: класс B не расширяет класс A
class B
{
public function
callNonStaticMethodOfA()
{
A::test();
}
}

(new
B())
->
callNonStaticMethodOfA()
;

?>

Результат выполнения приведённого примера в PHP 5.6:

Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8
object(B)#1 (0) {
}

Результат выполнения приведённого примера в PHP 7:

Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8

Notice: Undefined variable: this in /tmp/test.php on line 3
NULL

Ключевое слово yield теперь право-ассоциативный оператор

Конструкция yield больше не требует скобок и изменилась на право-ассоциативный оператор с приоритетом между языковой конструкцией print и оператором =>. Иногда это изменяет поведение кода:

<?php

echo yield -1;
// Раньше интерпретировалось так
echo (yield) - 1;
// А теперь так
echo yield (-1);

yield
$foo or die;
// Раньше интерпретировалось так
yield ($foo or die);
// А теперь так
(yield $foo) or die;

?>

Устранять неоднозначности помогают скобки.

В функциях нельзя определять параметры с одинаковыми именами

Больше нельзя определить в функции параметры с одинаковыми именами. Следующая функция выдаст ошибку уровня E_COMPILE_ERROR:

<?php

function foo($a, $b, $unused, $unused)
{
//
}

?>

Функции, которые работают с аргументами, теперь возвращают текущие значения аргументов

Функции func_get_arg(), func_get_args(), debug_backtrace() и трассировки исключений возвращают не исходные значения параметров, которые передали в функции в аргументах, а текущие значения параметров, которые к моменту возврата могли изменить значение.

<?php

function foo($x)
{
$x++;
var_dump(func_get_arg(0));
}

foo(1);

?>

Результат выполнения приведённого примера в PHP 5:

1

Результат выполнения приведённого примера в PHP 7:

2

Для оператора switch больше нельзя указывать больше одного блока default

В операторе switch больше невозможно задать больше одного блока default. Например, такая конструкция выдаст ошибку E_COMPILE_ERROR:

<?php

switch (1) {
default:
break;
default:
break;
}

?>

Удалили элемент суперглобального массива $HTTP_RAW_POST_DATA

Переменная $HTTP_RAW_POST_DATA больше недоступна. Вместо неё пользуются потоком php://input.

В INI-файлах запретили комментарии, которые начинались с символа #

Поддержку префикса комментария # в INI-файлах удалили. Вместо него пользуются префиксом ;. Это изменение касается как файла php.ini, так и файлов, которые обрабатываются функциями parse_ini_file() и parse_ini_string().

Модуль JSON заменили на JSOND

Модуль JSON заменили на JSOND, что порождает три небольших обратных несовместимости. Первое — числа нельзя заканчивать точкой, значения наподобие 34. требуется заменить на 34.0 или 34. Второе — в научной нотации экспоненте e нельзя следовать сразу за десятичной точкой, значения наподобие 3.e3 требуется заменить на 3.0e3 или 3e3. Третье — модуль не считает пустую строку корректным JSON-форматом.

Ошибки внутренних функций при переполнении

Раньше встроенные функции иногда без предупреждения обрезали числа, которые получили при приведении значений с типом float к значениям с типом integer, если float-значение оказывалось больше, чем вмещает integer. Теперь функции выдадут ошибку уровня E_WARNING и вернут null.

Исправление для значений, которые возвращает пользовательский обработчик сессии

Предикатные функции, которые реализовали через пользовательские обработчики сессии и которые возвращают значения false или -1, вызовут фатальную ошибку. Значения вызовут сбой и ошибку уровня E_WARNING, если из этих функций вернётся значение, которое отличается от логического, -1 или 0.

Порядок сортировки одинаковых элементов

Внутренний алгоритм сортировки улучшили. Изменение алгоритма иногда упорядочивает одинаковые элементы не так, как алгоритм делал это прежде.

Замечание:

Не полагайтесь на порядок одинаковых элементов, так как он изменится в любое время.

Изменение порядка обработки операторов break и continue

Операторы break и continue за пределами цикла или управляющей структуры switch теперь обрабатываются во время компиляции, а не во время выполнения, как это было раньше, поэтому выдают ошибки уровня E_COMPILE_ERROR.

Запретили константы как аргументы инструкций break и continue

Инструкции break и continue больше не принимают константу как аргумент и вызывают ошибку уровня E_COMPILE_ERROR.

Mhash больше не модуль

Модуль Mhash полностью интегрировали в модуль Hash. Поэтому больше невозможно определить доступность модуля Mhash функцией extension_loaded(); вместо неё пользуются функцией function_exists(). Кроме того, функция get_loaded_extensions() и функции, которые с ней связаны, больше не сообщают о модуле Mhash.

declare(ticks)

Директива declare(ticks) больше не проникает в отдельные единицы компиляции.

Добавить

Примечания пользователей

Пользователи ещё не добавляли примечания для страницы
To Top