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

### Ядро PHP

#### Сравнение строк с числами

Нестрогие сравнения чисел и нечисловых строк теперь работают как преобразование числа в строку с последующим сравнением строк. Сравнение чисел и числовых строк работает по прежним правилам. Поэтому сравнение наподобие `0 == "not-a-number"` теперь выдаст false.

Сравнение | До | После
--- | --- | ---
`0 == "0"` | `true` | `true`
`0 == "0.0"` | `true` | `true`
`0 == "foo"` | `true` | `false`
`0 == ""` | `true` | `false`
`42 == " 42"` | `true` | `true`
`42 == "42foo"` | `true` | `false`

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

- Слово `match` стало зарезервированным ключевым словом.

- Слово `mixed` стало зарезервированным, поэтому его нельзя указывать как название класса, интерфейса или трейта, и в пространствах имён.

- Ошибки утверждений теперь выбрасываются по умолчанию. Старое поведение устанавливается в INI-настройке `assert.exception=0`.

- Методы с названием как у класса больше не интерпретируются как конструкторы. Вместо этого определяют метод __construct().

- Нестатические методы теперь нельзя вызывать статически, поэтому функция is_callable() завершится ошибкой при проверке нестатического метода с названием класса, доступность вызова необходимо проверять с экземпляром объекта.

- Приведения типов `(real)` и `(unset)` удалили.

- INI-директиву track_errors удалили. Это означает, что php_errormsg больше не актуален. Вместо него пользуются функцией error_get_last().

- Больше нельзя определять константы без учёта регистра. Больше нельзя устанавливать для третьего параметра функции define() значение `true`.

- Больше нельзя указывать автозагрузчик через функцию __autoload(). Вместо этого рекомендуют пользоваться функцией spl_autoload_register().

- Аргумент `errcontext` больше не передаётся в пользовательские обработчики ошибок, которые задали функцией set_error_handler().

- Функцию create_function() удалили. Вместо неё пользуются анонимными функцииями.

- Функцию each() удалили. Вместо неё пользуются конструкцией `foreach` или классом ArrayIterator.

- Больше нельзя отвязать переменную this от замыканий, которые создали из методов Closure::fromCallable() или ReflectionMethod::getClosure().

- Больше нельзя отвязать переменную this от правильных замыканий, которые содержат this.

- Функцию array_key_exists() больше нельзя вызывать с объектами. Вместо этого можно использовать isset() или property_exists().

- Работа параметра `key` в функции array_key_exists() теперь приведена в соответствии с isset() и обычным доступом к массиву. Все типы ключей теперь используют обычное приведение типов, массив/объект к ключе приведёт к выбрасыванию TypeError.

- Любой массив, у которого в качестве первого числового ключа указано число n, будет использовать n+1 для своего следующего неявного ключа, даже если n отрицательно.

- Уровень error_reporting по умолчанию теперь `E_ALL`. Ранее он исключал `E_NOTICE` и `E_DEPRECATED`.

- display_startup_errors теперь включён по умолчанию.

- Использование parent внутри класса, у которого нет родителя, теперь приведёт к фатальной ошибке во время компиляции.

- Оператор `@` больше не подавляет фатальные ошибки (`E_ERROR`, `E_CORE_ERROR`, `E_COMPILE_ERROR`, `E_USER_ERROR`, `E_RECOVERABLE_ERROR`, `E_PARSE`). Обработчики ошибок, которые ожидают, что error_reporting будет иметь значение `0` при использовании оператора `@`, должны делать такие проверки через битовую маску:

      <?php
      // Замените это
      function my_error_handler($err_no, $err_msg, $filename, $linenum) {
          if (error_reporting() == 0) {
              return false;
          }
          // ...
      }

      // На это
      function my_error_handler($err_no, $err_msg, $filename, $linenum) {
          if (!(error_reporting() & $err_no)) {
              return false;
          }
          // ...
      }
      ?>

  Кроме этого, обязательно следует скрыть отображение сообщений об ошибках в производственной среде, которые могут привести к утечке информации. Проверьте, что `display_errors=Off` используется вместе с включённой записью журнала ошибок.

- `#[` больше не интерпретируется как начало комментария, так как этот синтаксис теперь используется для атрибутов.

- Ошибки наследования из-за несовместимых сигнатур методов (нарушения LSP) теперь всегда вызывают фатальную ошибку. Ранее в некоторых случаях выдавалось предупреждение.

- Приоритет оператора конкатенации изменился относительно сдвигов битов и сложения, а также вычитания.

      <?php
      echo "Сумма: " . $a + $b;
      // ранее интерпретировалось как:
      echo ("Сумма: " . $a) + $b;
      // сейчас интерпретируется как:
      echo "Сумма:" . ($a + $b);
      ?>

- Аргументы со значением по умолчанию, которое разрешается в `null` во время выполнения, больше не будут неявно помечать тип аргумента как nullable. Вместо этого нужно указывать либо явный тип, разрешающий значение null, либо явное значение `null` по умолчанию.

      <?php
      // Замените этот код:
      function test(int $arg = CONST_RESOLVING_TO_NULL) {}
      // На этот:
      function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
      // На этот (альтернативный вариант):
      function test(int $arg = null) {}
      ?>

- Ряд предупреждений преобразован в исключения Error:

  - Попытка записи в свойство несуществующего объекта. Ранее это неявно создавало объект stdClass в случае null, false и пустых строк.
  - Попытка добавить элемент в массив, для которого уже используется ключ PHP_INT_MAX.
  - Попытка использовать недопустимый тип (массив или объект) в качестве ключа массива или смещения строки.
  - Попытка записать в индекс массива скалярное значение.
  - Попытка распаковать значение, не являющее массивом/Traversable.
  - Попытка получить доступ к неквалифицированным константам, которые не определены. Ранее неквалифицированный доступ к константам приводил к предупреждению и интерпретировался как строка.
  - Передача неверного количества аргументов в невариативную встроенную функцию приведёт к исключению ArgumentCountError.
  - Передача недопустимых исчисляемых типов в функцию count() выбросит исключение TypeError.

  Ряд уведомлений преобразован в предупреждения:

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

- При попытке назначить несколько байтов смещению строки теперь будет выдано предупреждение.

- Неожиданные символы в исходных файлах (например, байты NUL за пределами строк) теперь будут приводить к исключению ParseError вместо предупреждения при компиляции.

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

- Фатальная ошибка времени компиляции "Only variables can be passed by reference" была отложена до времени выполнения и преобразована в исключение Error "Argument cannot be passed by reference".

- Некоторые уведомления "Only variables can be passed by reference" были преобразованы в исключение "Argument cannot be passed by reference".

- Сгенерированное имя для анонимных классов изменилось. Теперь он будет включать имя первого родителя или интерфейса:

      <?php
      new class extends ParentClass {};
      // -> ParentClass@anonymous
      new class implements FirstInterface, SecondInterface {};
      // -> FirstInterface@anonymous
      new class {};
      // -> class@anonymous
      ?>

  За новыми именами по-прежнему будет следовать NUL-байт и уникальный суффикс.

- Ссылки на неабсолютные трейты методов в адаптациях псевдонимов трейтов теперь должны быть однозначными:

      <?php
      class X {
          use T1, T2 {
              func as otherFunc;
          }
          function func() {}
      }
      ?>

  Если существуют и `T1::func()`, и `T2::func()`, этот код ранее принимался без уведомления, и предполагалось, что func ссылается на `T1::func`. Теперь вместо этого будет выброшена фатальная ошибка: необходимо явно указать `T1::func` или `T2::func`.

- Сигнатура абстрактных методов, определённых в трейтах, теперь проверяется по методу реализующего класса:

      <?php
      trait MyTrait {
          abstract private function neededByTrait(): string;
      }

      class MyClass {
          use MyTrait;

          // Ошибка из-за несоответствия типа возвращаемого значения.
          private function neededByTrait(): int { return 42; }
      }
      ?>

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

- Оболочки потока `data://` больше не доступны для записи, что соответствует документированному поведению.

- Арифметические и побитовые операторы `+`, `-`, `*`, `/`, `**`, `%`, `<<`, `>>`, `&`, `|`, `^`, `~`, `++`, `--` теперь будут последовательно выдавать TypeError, когда одним из операндов является массив (array), ресурс (resource) или не перегруженный объект (object). Единственным исключением из этого правила является операция слияния массивов `+`, которая по-прежнему поддерживается.

- Приведение с плавающей точкой в строку теперь всегда будет вести себя независимо от локали.

      <?php
      setlocale(LC_ALL, "de_DE");
      // Ранее:  3,14
      // Теперь: 3.14
      ?>

  Смотрите printf(), number_format() и NumberFormatter() для получения информации о способах настройки форматирования чисел.

- Удалена поддержка устаревших фигурных скобок для доступа к смещению.

      <?php
      // Вместо:
      $array{0};
      $array{"key"};
      // Используйте:
      $array[0];
      $array["key"];
      ?>

- Применение модификатора final к закрытому методу теперь приведёт к предупреждению, если этот метод не является конструктором.

- Если в конструкторе объекта используется exit(), то деструктор объекта больше не будет вызываться. Это соответствует поведению, когда конструктор выбрасывает исключение.

- Именам в пространстве имён больше нельзя содержать пробелы: имя `Foo\Bar` будет распознаваться как имя в пространстве имён, `Foo \ Bar` — нет. И наоборот, зарезервированные ключевые слова теперь разрешены в качестве сегментов пространства имён, что также может изменить интерпретацию кода: `new\x` теперь совпадает с `constant('new\x')`, но не с `new \x()`.

- Для вложенных тернарных операторов теперь требуется явное указание скобок.

- debug_backtrace() и Exception::getTrace() больше не будут предоставлять ссылки на аргументы. Невозможно изменить аргументы функции через трассировку.

- Обработка числовых строк была изменена, чтобы сделать её более понятной и менее подверженной ошибкам. Завершающие пробелы теперь разрешены в числовых строках для согласованности с тем, как обрабатываются начальные пробелы. В основном это влияет на:

  - Функцию is_numeric()
  - Сравнение строк со строками
  - Объявления типов
  - Операции увеличения и уменьшения

  Понятие "ведущая числовая строка" в основном было отброшено; случаи, когда это осталось, существуют для облегчения миграции. Строки, которые выдавали `E_NOTICE` "A non well-formed numeric value encountered", теперь будут выдавать `E_WARNING` "A non-numeric value encountered", а все строки, которые выдавали `E_WARNING` "A non-numeric value encountered" теперь будет выдавать TypeError. В основном это влияет на:

  - Арифметические операции
  - Побитовые операции

  Это изменение `E_WARNING` на TypeError также влияет на `E_WARNING` "Illegal string offset 'string'" для недопустимых смещений строки. Поведение явных приведений к int/float из строк не изменилось.

- Теперь у магических методов будут проверяться аргументы и возвращаемые типы, если они объявлены. Сигнатура должна соответствовать следующему списку:

  - `__call(string $name, array $arguments): mixed`
  - `__callStatic(string $name, array $arguments): mixed`
  - `__clone(): void`
  - `__debugInfo(): ?array`
  - `__get(string $name): mixed`
  - `__invoke(mixed $arguments): mixed`
  - `__isset(string $name): bool`
  - `__serialize(): array`
  - `__set(string $name, mixed $value): void`
  - `__set_state(array $properties): object`
  - `__sleep(): array`
  - `__unserialize(array $data): void`
  - `__unset(string $name): void`
  - `__wakeup(): void`

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

- Объявление функции с именем `assert()` внутри пространства имён больше не допускается и вызывает `E_COMPILE_ERROR`. Функция assert() подвергается специальной обработке со стороны движка, что может привести к несогласованному поведению при определении одноимённой функции в пространстве имён.

### Преобразование ресурсов в объекты

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

- curl_init() теперь возвращает объект CurlHandle вместо ресурса (resource). Функция curl_close() больше не имеет смысла, вместо этого экземпляр CurlHandle автоматически уничтожается, если на него больше нет ссылки.

- curl_multi_init() теперь возвращает объект CurlMultiHandle вместо ресурса (resource). Функция curl_multi_close() больше не имеет смысла, вместо этого экземпляр CurlMultiHandle автоматически уничтожается, если на него больше нет ссылки.

- curl_share_init() теперь возвращает объект CurlShareHandle вместо ресурса (resource). Функция curl_share_close() больше не имеет смысла, вместо этого экземпляр CurlShareHandle автоматически уничтожается, если на него больше нет ссылки.

- enchant_broker_init() теперь возвращает объект EnchantBroker вместо ресурса (resource).

- enchant_broker_request_dict() и enchant_broker_request_pwl_dict() теперь возвращают EnchantDictionary объект вместо ресурса (resource).

- Модуль GD теперь использует объекты GdImage в качестве базовой структуры данных для изображений, а не ресурсы (resource). Функция imagedestroy() больше не имеет смысла; вместо этого экземпляр GdImage автоматически уничтожается, если на него больше нет ссылки.

- openssl_x509_read() и openssl_csr_sign() теперь возвращают объект OpenSSLCertificate вместо ресурса (resource). Функция openssl_x509_free() объявлена устаревшей и больше не имеет смысла, вместо этого экземпляр OpenSSLCertificate автоматически уничтожается, если на него больше не ссылаются.

- openssl_csr_new() теперь возвращает объект OpenSSLCertificateSigningRequest вместо ресурса (resource).

- openssl_pkey_new() теперь возвращает объект OpenSSLAsymmetricKey вместо ресурса (resource). Функция openssl_pkey_free() объявлена устаревшей и больше не имеет смысла, вместо этого экземпляр OpenSSLAsymmetricKey автоматически уничтожается, если на него больше не ссылаются.

- shmop_open() теперь возвращает объект Shmop вместо ресурса (resource). Функция shmop_close() больше не имеет смысла и объявлена устаревшей; вместо этого экземпляр Shmop автоматически уничтожается, если на него больше не ссылаются.

- socket_create(), socket_create_listen(), socket_accept(), socket_import_stream(), socket_addrinfo_connect(), socket_addrinfo_bind() и socket_wsaprotocol_info_import() теперь возвращают объект Socket вместо ресурса (resource). socket_addrinfo_lookup() теперь возвращает массив объектов AddressInfo вместо массива ресурсов (resource).

- msg_get_queue() теперь возвращают объект SysvMessageQueue вместо ресурса (resource).

- sem_get() теперь возвращают объект SysvSemaphore вместо ресурса (resource).

- shm_attach() теперь возвращают объект SysvSharedMemory вместо ресурса (resource).

- xml_parser_create() и xml_parser_create_ns() теперь возвращают объект XMLParser вместо ресурса (resource). Функция xml_parser_free() больше не имеет смысла, вместо этого экземпляр XMLParser автоматически уничтожается, если на него больше не ссылаются.

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

- inflate_init() теперь возвращает объект InflateContext вместо ресурса (resource).

- deflate_init() теперь возвращает объект DeflateContext вместо ресурса (resource).

### COM и .Net (Windows)

Возможность импорта констант без учёта регистра из библиотек типов была удалена. Второй аргумент com_load_typelib() больше не может быть false; com.autoregister_casesensitive больше нельзя отключить; Маркеры без учёта регистра в com.typelib_file игнорируются.

### CURL

`CURLOPT_POSTFIELDS` больше не принимает объекты как массивы. Чтобы интерпретировать объект как массив, выполните явное приведение `(array)`. То же самое относится и к другим параметрам, принимающим массивы.

### Дата и время

Для работы функций mktime() и gmmktime() теперь требуется хотя бы один аргумент. time() может использоваться для получения текущей отметки времени.

### DOM

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

- DOMNameList
- DomImplementationList
- DOMConfiguration
- DomError
- DomErrorHandler
- DOMImplementationSource
- DOMLocator
- DOMUserDataHandler
- DOMTypeInfo
- DOMStringExtend

Удалены нереализованные методы модуля DOM, у которых не было реализации:

- DOMNamedNodeMap::setNamedItem()
- DOMNamedNodeMap::removeNamedItem()
- DOMNamedNodeMap::setNamedItemNS()
- DOMNamedNodeMap::removeNamedItemNS()
- DOMText::replaceWholeText()
- DOMNode::compareDocumentPosition()
- DOMNode::isEqualNode()
- DOMNode::getFeature()
- DOMNode::setUserData()
- DOMNode::getUserData()
- DOMDocument::renameNode()

### Enchant

- enchant_broker_list_dicts(), enchant_broker_describe() и enchant_dict_suggest() теперь возвращают пустой массив вместо `null`.

### Exif

read_exif_data() была удалена; Вместо неё следует использовать exif_read_data().

### Фильтрация данных

- Флаги `FILTER_FLAG_SCHEME_REQUIRED` и `FILTER_FLAG_HOST_REQUIRED` для фильтра `FILTER_VALIDATE_URL` были удалены. `scheme` и `host` необходимы (и всегда были).

- Типы `INPUT_REQUEST` и `INPUT_SESSION` для filter_input() и ей производных были удалены. Они никогда не были реализованы, а попытка их использования всегда приводила к вызову предупреждения.

### GD

- Устаревшие функции image2wbmp() были удалены.

- Устаревшие функции png2wbmp() и jpeg2wbmp() были удалены.

- Параметр `mode` по умолчанию для функции imagecropauto() больше не принимает значение `-1`. Вместо этого следует использовать `IMG_CROP_DEFAULT`.

- В Windows, php_gd2.dll переименован в php_gd.dll.

### GMP

gmp_random() была удалена. Вместо неё следует использовать gmp_random_range() или gmp_random_bits().

### Iconv

Реализации iconv, которые неправильно устанавливают errno в случае возникновения ошибок, больше не поддерживаются.

### IMAP

- Неиспользуемый аргумент `default_host` функции imap_headerinfo() был удалён.

- Функция imap_header(), которая является псевдонимом imap_headerinfo(), была удалена.

### Функции интернационализации

- Устаревшая константа `INTL_IDNA_VARIANT_2003` удалена.

- Устаревшая константа `Normalizer::NONE` удалена.

### LDAP

- Устаревшие функции ldap_sort(), ldap_control_paged_result() и ldap_control_paged_result_response() удалены.

- Изменился интерфейс ldap_set_rebind_proc(); параметр `callback` больше не принимает пустые строки; вместо этого следует указывать `null`.

### MBString

- Директива mbstring.func_overload была удалена. Связанные константы `MB_OVERLOAD_MAIL`, `MB_OVERLOAD_STRING` и `MB_OVERLOAD_REGEX` также были удалены. Наконец, записи `"func_overload"` и `"func_overload_list"` в mb_get_info() были удалены.

- mb_parse_str() больше нельзя использовать без передачи массива результатов.

- Удалён ряд устаревших псевдонимов mbregex. В следующем списке указано, какие функции следует использовать вместо них:

  - mbregex_encoding() → mb_regex_encoding()
  - mbereg() → mb_ereg()
  - mberegi() → mb_eregi()
  - mbereg_replace() → mb_ereg_replace()
  - mberegi_replace() → mb_eregi_replace()
  - mbsplit() → mb_split()
  - mbereg_match() → mb_ereg_match()
  - mbereg_search() → mb_ereg_search()
  - mbereg_search_pos() → mb_ereg_search_pos()
  - mbereg_search_regs() → mb_ereg_search_regs()
  - mbereg_search_init() → mb_ereg_search_init()
  - mbereg_search_getregs() → mb_ereg_search_getregs()
  - mbereg_search_getpos() → mb_ereg_search_getpos()
  - mbereg_search_setpos() → mb_ereg_search_setpos()

- Модификатор `e` для mb_ereg_replace() был удалён. Вместо него следует использоватьmb_ereg_replace_callback().

- Аргумент нестрокового шаблона для mb_ereg_replace() теперь будет интерпретироваться как строка вместо кодовой точки ASCII. Предыдущее поведение можно восстановить явным вызовом chr().

- Аргумент `needle` для функций mb_strpos(), mb_strrpos(), mb_stripos(), mb_strripos(), mb_strstr(), mb_stristr(), mb_strrchr() и mb_strrichr() теперь может быть пустым.

- Параметр `is_hex`, который не использовался для внутренних целей, был удалён из mb_decode_numericentity().

- Устаревшее поведение передачи кодировки в качестве третьего аргумента вместо смещения для функции mb_strrpos() было удалено; вместо этого в качестве четвёртого аргумента следует указать явное смещение `0` с кодировкой.

- Псевдонимы кодировки символов `ISO_8859-*` были заменены на псевдонимы `ISO8859-*` для лучшей совместимости с модулем iconv. Псевдонимы mbregex ISO 8859 с подчёркиванием (`ISO_8859_*` и `ISO8859_*`) также были удалены.

- mb_ereg() и mb_eregi() теперь будут возвращать логическое значение `true`, в случае найденного совпадения. Ранее они возвращали целое число `1`, если аргумент `matches` не был передан, или `max(1, strlen($matches[0]))`, если `matches` был не пустой.

### OCI8

- Класс OCI-Lob переименован в OCILob, а класс OCI-Collection — в OCICollection для имени совместимость обеспечивается средствами аннотации типа arginfo PHP 8.

- Некоторые функции псевдонимов объявлены устаревшим.

- oci_internal_debug() и её псевдоним ociinternaldebug() были удалены.

### ODBC

- odbc_connect() больше не использует соединения повторно.

- Неиспользуемый параметр `flags` функции odbc_exec() был удалён.

### OpenSSL

- openssl_seal() и openssl_open() теперь требуют передачи `method`, так как предыдущее значение по умолчанию `"RC4"` считается небезопасным.

### Регулярные выражения (совместимые с Perl)

При передаче недопустимых управляющих последовательностей они больше не интерпретируются как литералы. Такое поведение ранее требовало модификатора `X`, который теперь игнорируется.

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

- Режим обработки ошибок по умолчанию был изменён с "тихого" (silent) на "исключения" (exceptions). Подробнее смотрите Ошибки и обработка ошибок.

- Изменились сигнатуры некоторых методов PDO:

  - `PDO::query(string $query, ?int $fetchMode = null, mixed ...$fetchModeArgs)`
  - `PDOStatement::setFetchMode(int $mode, mixed ...$args)`

### PDO ODBC

Директива php.ini pdo_odbc.db2_instance_name была удалена.

### PDO MySQL

PDO::inTransaction() теперь сообщает о фактическом состоянии транзакции подключения, а не о приблизительном от PDO. Если запрос, при условии "неявной фиксации", выполняется, то PDO::inTransaction() впоследствии вернёт `false`, так как транзакция будет неактивной.

### PostgreSQL

- Устаревший синтаксис pg_connect() с использованием нескольких параметров вместо строки подключения больше не поддерживается.

- Устаревшие сигнатуры pg_lo_import() и pg_lo_export(), передающие соединение в качестве последнего аргумента, больше не поддерживаются. Вместо этого соединение должно быть передано первым аргументом.

- pg_fetch_all() теперь будет возвращать пустой массив вместо `false` для наборов результатов с отсутствующими строками.

### Phar

Метаданные, связанные с phar, больше не будут автоматически десериализоваться, чтобы исправить потенциальные уязвимости безопасности из-за создания экземпляров объекта, автозагрузки и т. д.

### Reflection

- Сигнатуры методов

  - `ReflectionClass::newInstance($args)`
  - `ReflectionFunction::invoke($args)`
  - `ReflectionMethod::invoke($object, $args)`

  были изменены на:

  - `ReflectionClass::newInstance(...$args)`
  - `ReflectionFunction::invoke(...$args)`
  - `ReflectionMethod::invoke($object, ...$args)`

  Код, который должен быть совместим как с PHP 7, так и с PHP 8, может использовать следующие сигнатуры:

  - `ReflectionClass::newInstance($arg = null, ...$args)`
  - `ReflectionFunction::invoke($arg = null, ...$args)`
  - `ReflectionMethod::invoke($object, $arg = null, ...$args)`

- Метод ReflectionType::__toString() теперь будет возвращать полное отладочное представление типа и больше не является устаревшим. В частности, результат будет включать индикатор допустимости значений NULL для типов, допускающих значение NULL. Формат возвращаемого значения нестабилен и может меняться в зависимости от версии PHP.

- Методы Reflection export() были удалены. Вместо этого объекты reflection могут быть преобразованы в строку.

- ReflectionMethod::isConstructor() и ReflectionMethod::isDestructor() теперь также возвращают `true` для методов интерфейсов __construct() и __destruct(). Раньше это было верно только для методов классов и трейтов.

- Метод ReflectionType::isBuiltin() перемещён в ReflectionNamedType. У ReflectionUnionType этого метода нет.

### Сокеты

- Устаревшие `flags` `AI_IDN_ALLOW_UNASSIGNED` и `AI_IDN_USE_STD3_ASCII_RULES` для socket_addrinfo_lookup() были удалены.

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

- SplFileObject::fgetss() был удалён.

- SplFileObject::seek() теперь всегда перемещается на начало строки. Ранее, позиция `>=1` перемещала к началу следующие строки.

- SplHeap::compare() теперь указывает сигнатуру метода. Наследующие классы, реализующие этот метод, теперь должны будут использовать совместимую сигнатуру метода.

- SplDoublyLinkedList::push(), SplDoublyLinkedList::unshift() и SplQueue::enqueue() теперь возвращают void вместо `true`.

- spl_autoload_register() теперь всегда будет выбрасывать TypeError для недопустимых аргументов, поэтому второй аргумент `do_throw` игнорируется, если для него установлено значение `false`.

- SplFixedArray теперь является IteratorAggregate, а не Iterator. SplFixedArray::rewind(), SplFixedArray::current(), SplFixedArray::key(), SplFixedArray::next() и SplFixedArray::valid() были удалены. Вместо них был добавлен SplFixedArray::getIterator(). Любой код, который использует явную итерацию над SplFixedArray, теперь должен получить Iterator с помощью SplFixedArray::getIterator(). Это означает, что SplFixedArray теперь безопасно использовать во вложенных циклах.

### Библиотека стандартных функций

- assert() больше не будет выполнять строковые аргументы, вместо этого они будут обрабатываться как любые обычные аргументы. Таким образом, вместо `assert('$a == $b')` следует использовать `assert($a == $b)`. INI-директива assert.quiet_eval и константа `ASSERT_QUIET_EVAL` были удалены, так как они больше не имеют смысла.

- parse_str() больше нельзя использовать без указания массива результатов.

- Фильтр string.strip_tags удалён.

- Аргумент `needle` функций strpos(), strrpos(), stripos(), strripos(), strstr(), strchr(), strrchr() и stristr() теперь всегда будет интерпретироваться как строка. Раньше нестрочные needles интерпретировались как кодовая точка ASCII. Явный вызов chr() может использоваться для восстановления предыдущего поведения.

- Аргумент `needle` функций strpos(), strrpos(), stripos(), strripos(), strstr(), stristr() и strrchr() теперь может быть пустым.

- Аргумент `length` функций substr(), substr_count(), substr_compare() и iconv_substr() теперь может быть `null`. Значения `null` означает отсутствие аргумента длины, и поэтому функции вернут остаток строки вместо пустой строки.

- Аргумент `length` функции array_splice() теперь может быть `null`. Передача значения `null` означает отсутствие аргумента, поэтому функция удалить все, начиная от `offset` до конца массива.

- Аргумент `args` функций vsprintf(), vfprintf() и vprintf() теперь должен быть массивом. Раньше принимался любой тип.

- Параметр `'salt'` функции password_hash() больше не поддерживается. Если используется опция `'salt'`, генерируется предупреждение, переданная соль игнорируется, а вместо неё используется сгенерированная соль.

- Функция quotemeta() теперь будет возвращать пустую строку, если была передана пустая строка. Ранее возвращалось `false`.

- Удалены следующие функции:

  - hebrevc()
  - convert_cyr_string()
  - money_format()
  - ezmlm_hash()
  - restore_include_path()
  - get_magic_quotes_gpc()
  - get_magic_quotes_runtime()
  - fgetss()

- `FILTER_SANITIZE_MAGIC_QUOTES` удалена.

- Вызов implode() с параметрами в обратном порядке `($pieces, $glue)` больше не поддерживается.

- parse_url() теперь будет различать отсутствующие и пустые запросы и фрагменты:

  - `http://example.com/foo → query = null, fragment = null`
  - `http://example.com/foo? → query = "", fragment = null`
  - `http://example.com/foo# → query = null, fragment = ""`
  - `http://example.com/foo?# → query = "", fragment = ""`
  Ранее во всех случаях query и fragment были `null`.

- var_dump() и debug_zval_dump() теперь будут печатать числа с плавающей точкой, используя serialize_precision, а не precision. В конфигурации по умолчанию это означает, что числа с плавающей точкой теперь печатаются с полной точностью этими функциями отладки.

- Если массив, возвращаемый __sleep(), содержит несуществующие свойства, теперь они автоматически проигнорируются. Ранее такие свойства были бы сериализованы, как если бы они имели значение `null`.

- Локаль по умолчанию при запуске теперь всегда будет определена как `"C"`. По умолчанию локали не наследуются из окружения. Ранее для `LC_ALL` было задано значение `"C"`, в то время как `LC_CTYPE` наследовался от окружения. Однако некоторые функции не учитывали унаследованную локаль без явного вызова setlocale(). Явный вызов setlocale() теперь требуется всегда, если компонент локали должен быть изменён с значения по умолчанию.

- Устаревший резервный вариант DES в crypt() был удалён. Если в crypt() передаётся неизвестный формат соли, функция завершится ошибкой с `*0` вместо возврата к слабому хешу DES.

- При указании значений вне допустимого диапазона для SHA256/SHA512 crypt() теперь будет выдана ошибка `*0` вместо ограничения до ближайшего предела. Это соответствует поведению glibc.

- Результат функций сортировки мог измениться, если в массиве есть одинаковые элементы.

- Любые функции, принимающие callback-функции, которые явно не указаны для приёма параметров по ссылке, теперь будут предупреждать, если используется callback-функция со ссылочными параметрами. Например, array_filter() и array_reduce(). Ранее так было у большинства функций, но не у всех.

- Обёртка HTTP-потока, используемая такими функциями, как file_get_contents(), теперь по умолчанию объявляет HTTP/1.1, а не HTTP/1.0. Это не меняет поведения клиента, но может заставить серверы реагировать по-другому. Чтобы сохранить старое поведение, установите параметр контекста потока `'protocol_version'`, например:

      <?php
      $ctx = stream_context_create(['http' => ['protocol_version' => '1.0']]);
      echo file_get_contents('http://example.org', false, $ctx);
      ?>

- Вызов crypt() без явной передачи соли больше не поддерживается. Если вы хотите создать надёжный хеш с автоматически сгенерированной солью, используйте вместо этого password_hash().

- substr(), mb_substr(), iconv_substr() и grapheme_substr() теперь последовательно фиксируют смещения за пределы границы строки. Ранее, в некоторых случаях, вместо пустой строки возвращался `false`.

- В Windows функции выполнения программ (proc_open(), exec(), popen() и т. д.) с использованием оболочки теперь последовательно выполняют %comspec% /s /c "$commandline", которая делает то же самое, что и выполнение $commandline (без дополнительных кавычек).

### Sysvsem

- Параметр `auto_release` в sem_get() был изменён, чтобы принимать логические значения (bool), а не целые числа (int).

### Tidy

- Параметр `use_include_path`, который не использовался внутренне, был удалён из tidy_repair_string().

- tidy::repairString() и tidy::repairFile() стали статическими методами.

### PHP-лексер (Tokenizer)

- В лексемах `T_COMMENT` больше не будет символа новой строки в конце. Вместо этого новая строка будет частью следующий лексемы `T_WHITESPACE`. Следует отметить, что за лексемой `T_COMMENT` не всегда идёт пробел, за ней также может следовать лексема `T_CLOSE_TAG` или конец файла.

- Имена пространств имён теперь представлены через лексемы `T_NAME_QUALIFIED` (`Foo\Bar`), `T_NAME_FULLY_QUALIFIED` (`\Foo\Bar`) и `T_NAME_RELATIVE` (`namespace\Foo\Bar`). PHP-лексер использует лексему `T_NS_SEPARATOR` только для автономных разделителей пространства имён и лексема синтаксически действительна только в сочетании с объявлениями группового использования.

### XMLReader

Методы XMLReader::open() и XMLReader::XML() стали статическими. Методы по-прежнему разрешается вызывать как методы экземпляра, но в классах-наследниках потребуется объявить методы статическими, если в дочернем классе они переопределяют методы родительского класса.

### XML-RPC

Модуль XML-RPC был перемещён в PECL и больше не является частью дистрибутива PHP.

### Zip

`ZipArchive::OPSYS_Z_CPM` была удалена (в этом имени была опечатка). Используйте вместо неё `ZipArchive::OPSYS_CPM`.

### Zlib

- gzgetss() удалена.

- zlib.output_compression больше не отключается автоматически для `Content-Type: image/*`.

### Пакеты тестов PHP для Windows

Скрипт выполнения тестов был переименован из run-test.php в run-tests.php, чтобы соответствовать его имени в php-src.

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