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

### Ядро PHP

#### Ограничения доступа к суперглобальной переменной $GLOBALS

Доступ к массиву $GLOBALS теперь имеет ряд ограничений. Чтение и запись отдельных элементов массива, как например, `$GLOBALS['var']`, по-прежнему работает. Чтение всего массива $GLOBALS также поддерживается. Однако операции, связанные с изменением всего $GLOBALS, запрещены. Например, `array_pop($GLOBALS)` приведёт к ошибке.

#### Использование static-переменных в унаследованных методах

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

    <?php
    class A {
        public static function counter() {
            static $counter = 0;
            $counter++;
            return $counter;
        }
    }
    class B extends A {}
    var_dump(A::counter()); // int(1)
    var_dump(A::counter()); // int(2)
    var_dump(B::counter()); // int(3), ранее было int(1)
    var_dump(B::counter()); // int(4), ранее было int(2)
    ?>

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

#### Необязательные параметры, указанные перед обязательными параметрами

Необязательный параметр, указанный перед обязательными параметрами, теперь всегда обрабатывается как обязательный, даже при вызове с использованием именованных аргументов. Начиная с PHP 8.0.0, но до PHP 8.1.0, приведённый ниже код выдаёт предупреждение об устаревании определения, но успешно выполняется при вызове. Начиная с PHP 8.1.0, выдаётся ошибка класса ArgumentCountError, как это было бы при вызове с позиционными аргументами.

    <?php
    function makeyogurt($container = "миску", $flavour)
    {
        return "Готовим $container с $flavour йогуртом.\n";
    }
    try
    {
        echo makeyogurt(flavour: "малиновым");
    }
    catch (Error $e)
    {
        echo get_class($e), ' - ', $e->getMessage(), "\n";
    }
    ?>

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

    Deprecated: Required parameter $flavour follows optional parameter $container
     in example.php on line 3
    Готовим миску с малиновым йогуртом.

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

    Deprecated: Optional parameter $container declared before required parameter
     $flavour is implicitly treated as a required parameter in example.php on line 3
    ArgumentCountError - makeyogurt(): Argument #1 ($container) not passed

Обратите внимание, что значение по умолчанию `null` может использоваться перед обязательными параметрами для указания типа, допускающего значение null, но этот параметр всё равно будет обязательным.

#### Совместимость типа возвращаемого значения с внутренними классами

Большинство неокончательных внутренних методов теперь требуют переопределяющих методов для объявления совместимого возвращаемого типа, в противном случае во время проверки наследования выдаётся уведомление об устаревании возможности. В случае, если тип возвращаемого значения не может быть объявлен для метода переопределения из-за проблем совместимости версий PHP, можно добавить атрибут ReturnTypeWillChange, чтобы заглушить уведомление об устаревании.

#### Новые ключевые слова

`readonly` теперь является ключевым словом. Однако его можно использовать как имя функции.

`never` теперь является зарезервированным словом, поэтому его нельзя использовать для названия класса, интерфейса или трейта, а также запрещено использовать в пространствах имён.

### Переход от ресурсов к объектам

Несколько ресурсов (resource) теперь представлены как объекты (object). Проверки возвращаемого значения с использованием функции is_resource() следует заменить проверками на `false`.

- Функции FileInfo теперь принимают и возвращают объекты finfo вместо ресурсов (resource) `fileinfo`.

- Функции FTP теперь принимают и возвращают объекты FTP\Connection вместо ресурсов (resource) `ftp`.

- Функции IMAP теперь принимают и возвращают объекты IMAP\Connection вместо ресурсов (resource) `imap`.

- The LDAP теперь принимают и возвращают объекты LDAP\Connection вместо ресурсов (resource) `ldap link`.

- Функции LDAP теперь принимают и возвращают объекты LDAP\Result вместо ресурсов (resource) `ldap result`.

- Функции LDAP теперь принимают и возвращают объекты LDAP\ResultEntry вместо ресурсов (resource) `ldap result entry`.

- Функции PgSQL теперь принимают и возвращают объекты PgSql\Connection вместо ресурсов (resource) `pgsql link`.

- Функции PgSQL теперь принимают и возвращают объекты PgSql\Result вместо ресурсов (resource) `pgsql result`.

- Функции PgSQL теперь принимают и возвращают объекты PgSql\Lob вместо ресурсов (resource) `pgsql large object`.

- Функции PSpell теперь принимают и возвращают объекты PSpell\Dictionary вместо ресурсов (resource) `pspell`.

- Функции PSpell теперь принимают и возвращают объекты PSpell\Config вместо ресурсов (resource) `pspell config`.

### MySQLi

Функции mysqli_fetch_fields() и mysqli_fetch_field_direct() теперь всегда возвращают `0` в свойстве max_length. Это значение можно вычислить, перебирая набор результатов и выбирая максимальную длину. Такой алгоритм раньше использовал PHP.

Опция `MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH` больше не имеет смысла.

Опция `MYSQLI_STORE_RESULT_COPY_DATA` больше не имеет смысла. Передача какого-либо значения в параметр `mode` метода mysqli::store_result() больше не имеет смысла.

mysqli::connect() теперь возвращает `true` вместо `null` в случае успешного выполнения.

Режим обработки ошибок по умолчанию был изменён с "silent" на "exceptions". Смотрите страницу Режимы обработки ошибок MySQLi для получения дополнительных сведений о том, что это влечёт за собой и о том, как явно установить этот атрибут. Чтобы восстановить предыдущее поведение, используйте: `mysqli_report(MYSQLI_REPORT_OFF);`

Классы, расширяющие mysqli_stmt::execute(), теперь должны указывать дополнительный необязательный параметр.

### MySQLnd

INI-директива mysqlnd.fetch_data_copy была удалена. Это не должно приводить к видимым для пользователя изменениям в поведении.

### OpenSSL

Секретные ключи EC теперь будут экспортироваться в формате PKCS#8, а не в традиционном формате, как и все другие ключи.

Функции openssl_pkcs7_encrypt() и openssl_cms_encrypt() теперь по умолчанию используют шифр AES-128-CBC, а не RC2-40. Шифр RC2-40 считается небезопасным и не включён по умолчанию в OpenSSL 3.

### Объекты данных PHP

Атрибут `PDO::ATTR_STRINGIFY_FETCHES` теперь преобразовывает логические значения (bool) в `"0"` или `"1"`. Ранее логические значения (bool) не были строковыми.

Вызов PDOStatement::bindColumn() с `PDO::PARAM_LOB` теперь будет постоянно связывать результат потока, если `PDO::ATTR_STRINGIFY_FETCHES` не включён. Раньше результатом был либо поток, либо строка в зависимости от используемого драйвера базы данных и времени выполнения привязки.

#### Драйвер MySQL

Целые числа и числа с плавающей запятой в наборах результатов теперь будут возвращаться с использованием собственных типов PHP вместо строк (string) при использовании эмулированных подготовленных операторов. Это соответствует поведению собственных подготовленных операторов. Предыдущее поведение можно восстановить, включив опцию `PDO::ATTR_STRINGIFY_FETCHES`.

#### Драйвер SQLite

Целые числа и числа с плавающей запятой в наборах результатов теперь будут возвращаться с использованием собственных типов PHP. Предыдущее поведение можно восстановить, включив опцию `PDO::ATTR_STRINGIFY_FETCHES`.

### Phar

Чтобы соответствовать интерфейсу ArrayAccess, Phar::offsetUnset() и PharData::offsetUnset() больше не возвращают логическое значение (bool).

### Стандартные функции

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

Функции htmlspecialchars(), htmlentities(), htmlspecialchars_decode(), html_entity_decode() и get_html_translation_table() теперь по умолчанию используют `ENT_QUOTES | ENT_SUBSTITUTE` вместо `ENT_COMPAT`. Это означает, что теперь `'` экранируется в `&#039;`. Кроме того, в случае неправильного UTF-8 вместо пустой строки будет возвращён замещающий символ Unicode.

debug_zval_dump() теперь выводит refcount ссылочных оболочек с их refcount, вместо того, чтобы просто добавлять `&` к значению. Это более точно моделирует эталонное представление, начиная с PHP 7.0.

debug_zval_dump() теперь выводит `interned` вместо фиктивного refcount для интернированных строк и неизменяемых массивов.

### Стандартная библиотека PHP (SPL)

SplFixedArray теперь будет закодирован в JSON как массив (array).

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open