PHP 8.1.28 Released!

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

Ядро 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 теперь зарезервированное слово, поэтому его нельзя использовать для названия класса, интерфейса или черты, а также запрещено использовать в пространствах имён.

  • Ошибки утверждений (assertions) теперь выбрасываются по умолчанию. Если предпочтительнее старое поведение, assert.exception=0 можно установить в INI-настройках.

  • Методы с именем как у класса больше не интерпретируются как конструкторы. Вместо этого следует использовать метод __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.

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

Exif

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

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

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

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. В следующем списке указано, какие функции следует использовать вместо них:

  • Модификатор 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)

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

  • 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.

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

  • 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

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

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

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

add a note

User Contributed Notes 3 notes

up
5
aphpguy at galaxy dot za dot net
9 months ago
If you have older projects that break with PHP7 to 8 migration due to the loose comparison issue:

i.e. if ($a == 0) different behaviour between PHP 7 and PHP 8
(for case like $a = "" or $a = "123foo" and other cases listed at top)

replace in old code:

if ($a == 0) { .. }

with

if (cmp_eq($a, $b)) { .. }

Tested with a wide range of scenarios, even against arrays, booleans, file handles, pipe handles, objects, scalars and numbers.

So old code still behave like before.
Then both PHP8.x and older PHP up to ver 7.x will give the exact same boolean true or false output for loose comparisons.

function cmp_eq($a, $b) {
// If both $a and $b are of type strings, compare them as strings
if (is_string($a) && is_string($b)) { return $a == $b; } // may not be === because php says '42' equals '042' true yet '42' === '042' is false.

// If both $a and $b are numeric strings, compare them as numbers
if (is_numeric($a) && is_numeric($b)) { return $a == $b; }

// If $a is an empty string and $b is 0, or vice versa, return true
if (($a === '' && $b === 0) || ($a === 0 && $b === '')) { return true; }

// If $a is a non-numeric string and $b is 0, or vice versa, return true
if ((is_string($a) && ($a !== '') && ($b === 0)) || (($a === 0) && is_string($b) && ($b !== ''))) {
return true;
}
// special case '123abc' == 123 .. php 7 casts 123abc to 123, then 123 == 123 results in true. lets mimic that.
if ((is_string($a) && ($a !== '') && (is_numeric($b)) && ((bool)$b))) {
$number = filter_var($a, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); //"-234.56xyz"
return $number == $b;
}
if (is_numeric($a) && ((bool)$a) && is_string($b) && ($b !== '')) {
$number = filter_var($b, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); //"-234.56xyz"
return $a == $number;
}

// If $a is a number and $b is a non-numeric string, cast $a to string and compare
if (is_numeric($a) && is_string($b)) { return strval($a) == $b; }

// If $b is a number and $a is a non-numeric string, cast $b to string and compare
if (is_string($a) && is_numeric($b)) { return $a == strval($b); }

// If $a and $b are both non-numeric strings, compare them directly, we should return true if they are the same
return $a == $b;
} // end func cmp_eq

Note: the better way would be to port code to PHP 8, use strict variable typing and rather make use of the === and !== operators.

But in some cases having lots of old code to quickly patch, this might help.
up
20
retry, abort, fail
2 years ago
The change in string to int comparison mentioned above (e.g. '' == 0 now equates to false) has some other nasty consequences:

$a = '';

// php 8

if ( $a < 0 ) echo 'true'; // echos true
if ( $a < -1) echo 'true'; // echos true
if ( $a < -100 ) echo 'true'; // echos true

// php 7

if ( $a < 0 ) echo 'true'; // no output
if ( $a < -1) echo 'true'; // no output
if ( $a < -100 ) echo 'true'; // no output

So in a situation where you may have a web form input and expected an empty value to equate to 0, watch out not only for == 0, != 0, and <= 0 comparisons, but ALL < or <= comparisons to negative integers.
up
-5
1035041238 at qq dot com
1 year ago
In PHP 8, an empty string is less than any number, an English letter is always bigger than any number.

More interesting are the punctuation marks and non-word characters, some bigger than numbers, some smaller than numbers

$string = '`~!@#$%^&*()-_=+[]{};:\'"\\|,.<>/?';

$number = 999999999999;

$str_len = strlen($string);

$bigger = $smaller = $equal = [];
for ( $i = 0; $i < $str_len; ++$i ) {
if ( $string[$i] > $number ) {
$bigger[] = $string[$i];
} elseif ( $string[$i] < $number ) {
$smaller[] = $string[$i];
} else {
$equal[] = $string[$i];
}
}

var_dump( $bigger ); //['`', '~', '@', '^', '_', '=', '[', ']', '{', '}', ';', ':', '\', '|', '<', '>', '?']
var_dump( $smaller); //['!', '#', '$', '%', '&', '*', '(', ')', '-', '+', ''', '"', ',', '.', '/']
var_dump( $equal); //[]
To Top