PHP 8.6 UPGRADE NOTES 1. Backward Incompatible Changes 2. New Features 3. Changes in SAPI modules 4. Deprecated Functionality 5. Changed Functions 6. New Functions 7. New Classes and Interfaces 8. Removed Extensions and SAPIs 9. Other Changes to Extensions 10. New Global Constants 11. Changes to INI File Handling 12. Windows Support 13. Other Changes 14. Performance Improvements ======================================== 1. Backward Incompatible Changes ======================================== - Core: . ??/empty() on a magic property no longer call __get() when __isset() has materialized the property by writing into the property table. The freshly-written value is returned directly. isset() is unaffected. - COM: . It is no longer possible to clone variant objects because the cloning behavior was ill-defined. - Curl: . The callback registered with CURLOPT_READFUNCTION now throws a ValueError when returning an integer other than 0, CURL_READFUNC_ABORT or CURL_READFUNC_PAUSE. - DOM: . Properties previously documented as @readonly (e.g. DOMNode::$nodeType, DOMDocument::$xmlEncoding, DOMEntity::$actualEncoding, DOMEntity::$encoding, DOMEntity::$version) are now declared with asymmetric visibility (public private(set)). Attempts to write to them from outside the class now raise "Cannot modify private(set) property ::$ from global scope" instead of the prior readonly modification error. ReflectionProperty::isWritable() also reports these properties accurately. . Array access on Dom\DtdNamedNodeMap objects now returns null for negative integer indexes instead of returning the first node. . Array access on Dom\DtdNamedNodeMap objects now raises a ValueError when the integer index is greater than INT_MAX instead of overflowing to a smaller index. - GD: . imagesetstyle(), imagefilter() and imagecrop() filter the types / values of their array arguments and raise a TypeError / ValueError accordingly. . imageaffinematrixget() now enforces the documented array|float type for the $options parameter, including the corresponding weak and strict typing behavior. - GMP: . GMP power and shift operators now throw a ValueError when GMP right operands are outside the unsigned long range, instead of silently truncating them. . GMP integer string parsing now throws a ValueError for strings containing NUL bytes, instead of silently truncating them. - Intl: . Passing a non-stringable object as a time zone to Intl APIs that accept time zone objects or strings now raises a TypeError instead of an Error. . IntlIterator::current() now returns null when called before the iterator is positioned, or after the iterator becomes invalid, instead of exposing an undefined value. . IntlBreakIterator::getLocale() now raises a ValueError when the type is neither Locale::ACTUAL_LOCALE nor Locale::VALID_LOCALE instead of returning false. . MessageFormatter::parse() and parseMessage() now return PHP_INT_MIN as int, rather than float, on 64-bit platforms when parsing integer values. . The $type parameter of IntlBreakIterator::getPartsIterator() has been changed from string to int to match the underlying implementation. . UConverter::transcode() now rejects from_subst and to_subst option values longer than 127 bytes instead of silently truncating the length before passing it to ICU. . ResourceBundle::get() and resourcebundle_get() now report fallback-disabled resource lookups with "without fallback to " instead of the malformed "without fallback from to ". . IntlDateFormatter::parse()/datefmt_parse() and IntlDateFormatter::localtime()/datefmt_localtime() now raise a TypeError when the offset argument is not of type int instead of silently converting the value. . Collator::sort(), collator_sort(), Collator::asort(), and collator_asort() now report UTF-8/UTF-16 conversion failures during comparison through the intl error mechanism and return false. With intl.use_exceptions enabled, these failures throw IntlException. Previously, these paths emitted a warning and compared the value as an empty string. - PCNTL: . pcntl_alarm() now raises a ValueError if the seconds argument is lower than zero or greater than the platform's UINT_MAX. . pcntl_exec() now raises a ValueError if the $args argument is not a list array. - PCRE: . preg_grep() now returns false instead of a partial array when a PCRE execution error occurs (e.g. malformed UTF-8 input with the /u modifier). This is consistent with other preg_* functions. - PGSQL: . pg_fetch_object() now reports the ValueError for a non-empty $constructor_args on a class without a constructor on the $constructor_args argument instead of $class. Errors raised when the requested class is not instantiable (abstract, interface, enum) now surface before the row is fetched. - Phar: . Phar::mungServer() now raises a ValueError when an invalid argument value is passed instead of being silently ignored. . Phar::addEmptyDir() now rejects "/.phar" paths in addition to ".phar" paths, and raises the same BadMethodCallException for attempts to create the reserved magic ".phar" directory through that form. . Phar::addEmptyDir() now treats non-magic names that merely share the ".phar" prefix as ordinary directories. . Files are only automatically interpreted as Phar archives when included if ".phar" occurs as an extension in the filename component of their paths. Previously, it could occur in a directory name or as part of an extension such as ".pharma". - Posix: . posix_access() now raises a ValueError when an invalid $flags argument value is passed. . posix_mkfifo() now raises a ValueError when an invalid $permissions argument value is passed. - Session: . Setting session.cookie_path, session.cookie_domain, or session.cache_limiter to a value containing NUL bytes now emits a warning and leaves the setting unchanged. Previously, NUL bytes were silently accepted: for cookie_path and cookie_domain this caused the SAPI to drop the Set-Cookie header; for cache_limiter the value was silently truncated at the NUL byte. . A ValueError is not thrown if $name is a string containing NUL bytes in session_module_name(). . session_encode() now returns an empty string instead of false for empty sessions. It only returns false now when the session data could not be encoded. This mainly happens with the default serialization handler if a key contains the pipe | character. . When session.lazy_write is enabled and a session handler implements SessionUpdateTimestampHandlerInterface, sessions that were read as empty and remain empty at write time will now trigger updateTimestamp() instead of write(). Previously, write() was always called for empty sessions because session_encode() returned false, bypassing the lazy_write comparison. Custom session handlers that rely on write() being called with empty data (e.g. to destroy the session) should implement the same logic in their updateTimestamp() method. . The defaults of three session INI settings have changed to provide secure behavior out of the box: - session.use_strict_mode is now 1 (was 0). Strict mode rejects uninitialized session IDs, mitigating session fixation. Custom session handlers that previously relied on accepting externally supplied IDs without a corresponding storage entry must either implement validateId() / create_sid() or explicitly set this to 0. - session.cookie_httponly is now 1 (was 0). Session cookies are no longer accessible to JavaScript via document.cookie. Applications that read the session cookie from JavaScript must explicitly set this to 0. - session.cookie_samesite is now "Lax" (was unset). Session cookies are no longer sent on cross-site requests other than top-level navigations using safe HTTP methods. Applications that depend on session cookies being sent on cross-site POST submissions must explicitly set this to "None" (and also set session.cookie_secure to 1). RFC: https://wiki.php.net/rfc/session_security_defaults . SessionHandler::validateId() has been added and delegates to the configured save handler. A subclass that declares validateId() without a return type now emits a deprecation notice for the tentative bool return type. A subclass that overrides open() without calling parent::open() keeps its previous behavior and emits a warning when an ID is validated. - Shmop: . shmop_open() now raises a ValueError when the $key argument is outside the platform's key_t range instead of passing a truncated key to the operating system. - SimpleXML: . SimpleXMLElement::__construct() now raises a ValueError when the $data argument contains NUL bytes, matching simplexml_load_file(). With $dataIsURL set, it previously truncated the path at the first NUL byte. Without it, the string went to libxml, which with default options rejects a NUL on current versions but accepts the truncated document on older ones and under LIBXML_RECOVER. - SOAP: . The "classmap" option of SoapClient and SoapServer now rejects arrays containing integer keys. Previously, sparse integer-keyed and mixed-keyed arrays could be accepted. SoapClient now throws TypeError for non-array "classmap" options and ValueError for arrays containing integer keys, also when the "exceptions" option is disabled. . WSDL/XML Schema parsing now rejects out-of-range integer values for occurrence constraints and integer restriction facets. Negative minOccurs and maxOccurs values are rejected as well. . SOAP encoding errors now report the affected type or failing operation in the error message instead of the generic "Encoding: Violation of encoding rules" message. Code that compares the exact message may need to be updated. - Sockets: . socket_set_option() with SO_ATTACH_REUSEPORT_CBPF now requires an int $value and a $level of SOL_SOCKET. Any other value type throws a TypeError instead of being coerced, and any other level raises a warning and returns false. . socket_set_option() with SO_ATTACH_REUSEPORT_CBPF and a $value of 0 now detaches the reuseport filter through SO_DETACH_REUSEPORT_BPF. It previously used SO_DETACH_BPF, an alias of SO_DETACH_FILTER, which left the reuseport program attached. - Sodium: . The password-hashing functions sodium_crypto_pwhash(), sodium_crypto_pwhash_str(), sodium_crypto_pwhash_scryptsalsa208sha256() and sodium_crypto_pwhash_scryptsalsa208sha256_str() now throw ValueError instead of SodiumException when an argument is out of range, such as an opslimit or memlimit below the documented minimum. SodiumException is still thrown for internal libsodium failures. - SPL: . SplObjectStorage::getHash() implementations may no longer mutate any SplObjectStorage instance. Attempting to do so now throws an Error. . SplFileObject::next() now advances the stream when no prior current() call has cached a line. A subsequent current() call returns the new line rather than the previous one. . SplFileObject::fgets() no longer caches the returned line for subsequent current() calls. current() now re-reads from the current stream position instead of returning the line fgets() just returned. . SplFileObject::next() past EOF no longer increments key() without bound. SplFileObject::seek() past EOF now produces the same key() value as SplTempFileObject; the two previously returned different values. . DirectoryIterator::key() now returns int|string, and DirectoryIterator::current() returns string|SplFileInfo|static. - Standard: . array_intersect() with at least two arrays now converts values to strings while scanning its inputs instead of during sort comparisons. This can change the number and order of conversion warnings and __toString() calls, which conversion exception is reached, and the result for stateful __toString() implementations. Argument types are validated before checking for empty arrays or converting values, so an invalid later argument can suppress conversion side effects from earlier arrays. Values are not converted if any input array is empty. . Form feed (\f) is now added to the default trimmed characters of trim(), rtrim() and ltrim(). RFC: https://wiki.php.net/rfc/trim_form_feed . array_filter() now raises a ValueError when an invalid $mode argument value is passed. . array_change_key_case() now raises a ValueError when an invalid $case argument value is passed. . getenv() and putenv() now raise a ValueError when the first argument contains NUL bytes. . dl() now raises a ValueError when the $extension_filename argument contains NUL bytes. . openlog() now raises a ValueError when the $prefix argument contains NUL bytes. . parse_str() now raises a ValueError when the $string argument contains NUL bytes. . setlocale() now raises a ValueError when a locale name contains NUL bytes, instead of silently truncating it. Arrays are now accepted only for the $locales argument. Passing an array as a later variadic locale argument now throws a TypeError. Passing any additional locale arguments when $locales is an array now throws an ArgumentCountError. . linkinfo() now raises a ValueError when the $path argument is empty. . pathinfo() now raises a ValueError when an invalid $flag argument value is passed. . scandir() now raises a ValueError when an invalid $sorting_order argument value is passed. . number_format() now raises a ValueError when $decimals is outside the integer range instead of silently clamping very large positive values. . sleep() now raises a ValueError when $seconds is greater than the platform limit (UINT_MAX seconds, or UINT_MAX / 1000 seconds on Windows) instead of allowing the value to overflow. . usleep() now raises a ValueError when $microseconds is greater than UINT_MAX instead of allowing the value to overflow. . proc_open() now raises a ValueError when the $cwd argument contains NUL bytes. . base_convert(), bindec(), hexdec() and octdec() now raise a notice when they cannot precisely convert the given number. . The following functions now raise a ValueError when the $filename argument contains NUL bytes: - fileperms() - fileinode() - filesize() - fileowner() - filegroup() - fileatime() - filemtime() - filectime() - filetype() - is_writable() - is_readable() - is_executable() - is_file() - is_dir() - is_link() - file_exists() - lstat() - stat() . unpack() now reads a "<" or ">" immediately following a format code as an endianness modifier rather than as the first character of the element name. Formats such as "sname" raises a ValueError because the C format code accepts no endianness modifier. A name starting with these characters is unaffected when a repeater precedes it, as in "s1prop = $val. RFC: https://wiki.php.net/rfc/const_object_property_write - Curl: . curl_getinfo() return array now includes a new size_delivered key, which indicates the total number of bytes passed to the download write callback. This value can also be obtained by passing CURLINFO_SIZE_DELIVERED as the $option parameter. Requires libcurl 8.20.0 or later. . Added CURLOPT_SEEKFUNCTION to register a callback that repositions a streamed request body so libcurl can rewind and resend it on a redirect, multi-pass authentication, or a retried reused connection instead of failing with CURLE_SEND_FAIL_REWIND. The callback receives the CurlHandle, offset and origin, and must return one of CURL_SEEKFUNC_OK, CURL_SEEKFUNC_FAIL or CURL_SEEKFUNC_CANTSEEK. - Date: . Added a new Time\Duration class. RFC: https://wiki.php.net/rfc/duration_class - Fileinfo: . finfo_file() now works with remote streams. - GMP: . Added gmp_powm_sec() for side-channel quiet modular exponentiation. Requires GNU MP 5.0.0 or later; it is not available on official Windows builds using MPIR. . Added gmp_prevprime() to get the largest prime smaller than the given number. The optional $definitely_prime output parameter indicates whether the returned number is definitely prime, as opposed to probably prime. A ValueError is thrown if no such prime exists. This function is available only when PHP is built against GNU MP 6.3.0 or later; it is not available on official Windows builds using MPIR. - Intl: . Added the static methods IntlDatePatternGenerator::getSkeleton() and IntlDatePatternGenerator::getBaseSkeleton() to generate the unique skeleton and base skeleton for a date/time pattern. . Added Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue(), with the aliases locale_get_display_keyword() and locale_get_display_keyword_value(), respectively. RFC: https://wiki.php.net/rfc/getdisplaykeyword_and_getdisplaykeywordvalue . Added IntlNumberRangeFormatter class to format an interval of two numbers with a given skeleton, locale, IntlNumberRangeFormatter::COLLAPSE_AUTO, IntlNumberRangeFormatter::COLLAPSE_NONE, IntlNumberRangeFormatter::COLLAPSE_UNIT, IntlNumberRangeFormatter::COLLAPSE_ALL collapse and IntlNumberRangeFormatter::IDENTITY_FALLBACK_SINGLE_VALUE, IntlNumberRangeFormatter::IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, IntlNumberRangeFormatter::IDENTITY_FALLBACK_APPROXIMATELY and IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE identity fallbacks. It is supported as of ICU 63. . Added SpoofChecker::areBidiConfusable() to check whether two strings are confusable for a given text direction, along with the SpoofChecker::LTR and SpoofChecker::RTL direction constants. It is supported as of ICU 74. . Added SpoofChecker::getBidiSkeleton() to generate a confusable skeleton for a given text direction. It is supported as of ICU 74. . Added SpoofChecker::getSkeleton() to generate a confusable skeleton for a given string. - IO: . Added new polling API. RFC: https://wiki.php.net/rfc/poll_api - JSON: . Added extra info about error location to the JSON error messages returned from json_last_error_msg() and JsonException message. - OpenSSL: . Added TLS session resumption support for streams with new stream context options: session_data, session_new_cb, session_cache, session_cache_size, session_timeout, session_id_context, session_get_cb, session_remove_cb, and num_tickets. This allows saving and restoring client sessions across requests, implementing custom server-side session storage, and controlling session cache behavior. RFC: https://wiki.php.net/rfc/tls_session_resumption . Added TLS external PSK support for streams with new stream context options: psk_client_cb and psk_server_cb. This allows setting and receiving PSK. . Added TLS 1.3 early data (0-RTT) support for streams. Clients send early data with the early_data context option; servers accept it with max_early_data and receive it through the early_data_cb callback. The outcome is reported as 'accepted', 'rejected' or 'not_sent' in the early_data key of the crypto stream_get_meta_data() array. - PDO_PGSQL: . Added Pdo\Pgsql::ATTR_CHUNK_SIZE, the number of rows a statement fetches per chunk. A value of 1 or more enters the lazy fetch mode of PDO::ATTR_PREFETCH => 0. Setting PDO::ATTR_PREFETCH replaces the chunk size. Statements that are prepared with neither it nor PDO::ATTR_PREFETCH fall back to the value set on the connection. Requires libpq 17 or later. - Phar: . Overriding the getMTime() and getPathname() methods of SplFileInfo now influences the result of the phar buildFrom family of functions. This makes it possible to override the timestamp and names of files. - SNMP: . It is now possible to use AES192, AES192C, AES256, and AES256C as SNMPv3 security protocols if the underlying library supports them. RFC: https://wiki.php.net/rfc/snmp_improvements_2026#increase_the_number_of_snmpv3_security_protocols_supported . It is now possible to reset the MIB tree using the new snmp_init_mib() function. RFC: https://wiki.php.net/rfc/snmp_improvements_2026#allow_the_snmp_mib_to_be_reset . Additional MIB parsing and output control functionality has been exposed via the snmp_set_mib_option(), snmp_set_output_option(), snmp_set_string_output_format() functions, the $numeric_index, $numeric_timeticks, $extended_index, $dont_print_units, $escape_quotes, $print_hex_text SNMP properties, and the SNMP::setOidOutputFormat(), SNMP::setStringOutputFormat() methods. (eskyuu) RFC: https://wiki.php.net/rfc/snmp_improvements_2026#implement_more_mib_parsing_and_value_output_controls - Standard: . pack() and unpack() now accept the "<" and ">" endianness modifiers on the signed and unsigned integer format codes. RFC: https://wiki.php.net/rfc/pack-unpack-endianness-signed-integers-support . pack() and unpack() now accept the "<" and ">" endianness modifiers on the float and double format codes. RFC: https://wiki.php.net/rfc/pack-unpack-float-endianness-modifier - Streams: . Added new stream errors API including new classes, enums, functions and internal API. It is controlled using error_mode, error_store and error_handler stream context options. RFC: https://wiki.php.net/rfc/stream_errors . Added the "filter.max_filter_count" stream context option for php://filter URLs. When set, opening the stream fails with a warning if the URL would add more filters than the configured value. Negative values disable the check. RFC: https://wiki.php.net/rfc/limit-maximum-number-of-filter-chains . Added stream socket context option so_reuseaddr that allows disabling address reuse (SO_REUSEADDR) and explicitly uses SO_EXCLUSIVEADDRUSE on Windows. . Added stream socket context options so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt that allow setting socket keepalive options. . Added stream socket context option so_linger that sets SO_LINGER on TCP sockets. A positive value enables lingering for that many seconds, zero or a negative value disables it. Values above 65535 are clamped as the linger time is limited to an unsigned short on some platforms. . Allowed casting filtered streams as file descriptors for select. . Added the "write_seek_mode" filter parameter for the bz2, iconv, zlib, and string stream filters. This parameter must be set via an associative array where the key is "write_seek_mode" and the value is one of the following strings: "preserve", "reset", or "strict". - URI: . Added Uri\Rfc3986\Uri::getUriType() and Uri\WhatWg\Url::isSpecialScheme(). RFC: https://wiki.php.net/rfc/uri_followup#uri_type_detection . Added Uri\Rfc3986\Uri::getHostType() and Uri\WhatWg\Url::getHostType(). RFC: https://wiki.php.net/rfc/uri_followup#host_type_detection . Added Uri\Rfc3986\UriBuilder and Uri\WhatWg\UrlBuilder. RFC: https://wiki.php.net/rfc/uri_followup#uri_building . Added Uri\url_percent_encode(). RFC: https://wiki.php.net/rfc/uri_followup#percent-encoding_support ======================================== 3. Changes in SAPI modules ======================================== - CLI: . The built-in development server now accepts requests using the HTTP QUERY method instead of returning 501 Not Implemented. ======================================== 4. Deprecated Functionality ======================================== - Core: . Using "namespace" as a class constant name is deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_using_namespace_as_a_class_constant_name . Using the return statement in a finally block is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_returning_from_a_finally_block . Specifying a return type of array|null / ?array for __debugInfo() is now deprecated. Specify array instead. . Returning values from __construct() and __destruct() is now deprecated. RFC: https://wiki.php.net/rfc/deprecate-return-value-from-construct . Making __construct() and __destruct() a Generator is now deprecated. RFC: https://wiki.php.net/rfc/deprecate-return-value-from-construct . Naming a function readonly is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_the_possibility_to_name_a_function_readonly . Passing a 3rd argument to define() is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_define_with_case_insensitive_being_specified - BZ2: . Passing an object for the Bzip2 {de}compression stream filter is now deprecated. Use get_object_vars() on the object instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_as_parameters_to_the_bzip2decompress_and_bzip2compress_stream_filters - GMP: . The shift (<<, >>) and exponentiation (**) operators on GMP objects now emit a deprecation warning when converting a float right operand to int loses precision. - Mbstring: . Mbregex has been deprecated, because the underlying Oniguruma library is no longer maintained. RFC: https://wiki.php.net/rfc/eol-oniguruma . Passing objects to mb_convert_variables() is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_vars_parameter_of_mb_convert_variables - MySQLi: . The mysqli_get_charset() function and mysqli::get_charset() method are now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_mysqli_get_charset . The mysqli_stmt_init() function, mysqli::stmt_init() method, and calling the mysqli_stmt constructor without providing the $query parameter are now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_mysqlistmt_init - Reflection: . Calling ReflectionProperty::setValue() with an object that is not an instance of the class on which the property was declared is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types . Calling ReflectionProperty::setRawValue() with an object that is not an instance of the class on which the property was declared is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types . Calling ReflectionMethod::invoke() or ReflectionMethod::invokeArgs() with an object and a static method is now deprecated. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionmethodinvoke_and_reflectionmethodinvokeargs_with_objects_for_static_methods - Session: . It is now deprecated to pass an object that does not implement the create_sid() and validateId() methods. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_passing_a_sessionhandler_object_to_session_set_save_handler_which_does_not_contain_the_create_sid_and_validateid . A deprecation is now emitted when implementing SessionHandlerInterface on a class which doesn't define the create_sid() or validateId() methods, as those will be moved from SessionUpdateTimestampHandlerInterface and SessionIdInterface to SessionHandlerInterface. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_passing_a_sessionhandler_object_to_session_set_save_handler_which_does_not_contain_the_create_sid_and_validateid - SPL: . The spl_classes() function is now deprecated. Use ReflectionExtension::getClassNames() instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_spl_classes . The spl_object_hash() function is now deprecated. Use spl_object_id() instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_spl_object_hash . The following ArrayIterator methods are now deprecated: * ArrayIterator::getFlags() * ArrayIterator::setFlags() * ArrayIterator::asort() * ArrayIterator::ksort() * ArrayIterator::uasort() * ArrayIterator::uksort() * ArrayIterator::natsort() * ArrayIterator::natcasesort() * ArrayIterator::unserialize() * ArrayIterator::serialize() RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_arrayiterator_methods_that_inherit_arrayobject_implementation . The following SplFileObject methods are now deprecated: * SplFileObject::fgetcsv() * SplFileObject::fputcsv() * SplFileObject::setCsvControl() * SplFileObject::getCsvControl() RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_splfileobject_csv_methods - Standard: . metaphone() is deprecated. Please use a userland phonetic matching library instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_metaphone_function . Using more than 16 filters in a php://filter URL without configuring the "filter.max_filter_count" stream context option now emits an E_DEPRECATED warning. Use stream_filter_append() or configure this option explicitly. RFC: https://wiki.php.net/rfc/limit-maximum-number-of-filter-chains . Passing an object to array_walk{_recursive} is now deprecated. Use get_object_vars() on the object instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_array_parameter_of_array_walk_and_array_walk_recursive . The is_double() function is now deprecated. Use is_float() instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_is_double . The is_long() and is_integer() functions are now deprecated. Use is_int() instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_is_integer RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_is_long . The doubleval() function is now deprecated. Use floatval() instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_doubleval . The strcoll() function is now deprecated. Use Collator::compare() instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_strcoll . The SORT_LOCALE_STRING constant for the family of sort functions is now deprecated. Use one of the following functions instead: * Collator::sort() * Collator::asort() * Collator::sortWithSortKeys() RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_sort_locale_string_flag_for_sort_functions - Zlib: . Passing an object for the zlib deflate and inflate stream filter is now deprecated. Use get_object_vars() on the object instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_as_parameters_to_the_zlibinflate_and_zlibdeflate_stream_filters . Passing an object as the $option argument to deflate_init and inflate_init is now deprecated. Use get_object_vars() on the object instead. RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_options_parameter_of_deflate_init_and_inflate_init ======================================== 5. Changed Functions ======================================== - Filter: . filter_var_array() return type has been narrowed from array|false|null to array|false. The function always establishes an array before filtering, so null was never returned. filter_input_array() is unaffected: it still returns null when the requested superglobal does not exist. - GMP: . gmp_fact() now throws a ValueError if $num does not fit into an unsigned long. . gmp_pow(), gmp_binomial(), gmp_root() and gmp_rootrem() now throw a ValueError if their second argument does not fit into an unsigned long. . The shift (<<, >>) and exponentiation (**) operators on GMP objects now throw a ValueError if the right operand does not fit into an unsigned long. . gmp_powm() modulo-by-zero now raises a DivisionByZeroError whose message includes the function name and argument index ($modulus). - MySQLi: . The return structure of mysqli_get_charset() no longer contains the undocumented "comment" element. The value of "charsetnr" is now set to a constant 0 as this number was an implementation detail that should not have been exposed to the public. - OpenSSL: . Output of openssl_x509_parse() contains criticalExtensions listing all critical certificate extensions. . openssl_sign() and openssl_verify() now have an additional optional argument $salt_length that allows controlling the RSA-PSS salt length when OPENSSL_PKCS1_PSS_PADDING is used. It accepts an explicit length or one of the new OPENSSL_RSA_PSS_SALTLEN_* constants. - PDO_DBLIB: . When using persistent connections, there is now a liveness check in the constructor. - Phar: . Phar::mungServer() now supports reference values. - Readline: . readline_completion_function() now declares true as its return type. The function assigns a static callback and then tests whether the assignment landed, which is a tautology; an invalid callback throws a TypeError via ZPP before the function body is reached. - Sockets: . socket_addrinfo_lookup() now has an additional optional argument $error_code that, when not null, receives the error code on failure (one of the EAI_* constants). . socket_cmsg_space() return type has been narrowed from ?int to int. Every failure path has thrown a ValueError since PHP 8.0, so null was never returned. - Standard: . header_register_callback() now declares true as its return type. It has not been able to return false since PHP 8.0.0, when passing an invalid callback started throwing a TypeError instead. . register_tick_function() now declares true as its return type. It has always returned true on success; an invalid callback throws a TypeError via ZPP before the function body is reached. . ini_get_all() now includes a "builtin_default_value" element for each directive when $details is true. It holds the built-in default value of the directive (or null if it has none), independent of values set in php.ini, on the command line, or at runtime. - Zip: . zip_entry_close() return type has been narrowed from bool to true. The function already always returned true. ======================================== 6. New Functions ======================================== - GMP: . gmp_powm_sec() . gmp_prevprime() - Intl: . grapheme_strrev() RFC: https://wiki.php.net/rfc/grapheme_strrev . IntlDatePatternGenerator::getSkeleton() . IntlDatePatternGenerator::getBaseSkeleton() . Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue() RFC: https://wiki.php.net/rfc/getdisplaykeyword_and_getdisplaykeywordvalue . SpoofChecker::areBidiConfusable() . SpoofChecker::getBidiSkeleton() . SpoofChecker::getSkeleton() - MySQLi: . Added mysqli::quote_string() and mysqli_quote_string(). RFC: https://wiki.php.net/rfc/mysqli_quote_string - Reflection: . ReflectionConstant::inNamespace() . ReflectionProperty::isReadable() and ReflectionProperty::isWritable() RFC: https://wiki.php.net/rfc/isreadable-iswriteable . ReflectionParameter::getDocComment() RFC: https://wiki.php.net/rfc/parameter-doccomments . ReflectionAttribute::inNamespace() . ReflectionAttribute::getNamespaceName() . ReflectionAttribute::getShortName() - SNMP: . snmp_init_mib() . snmp_set_mib_option() . snmp_set_output_option() . snmp_set_string_output_format() - Standard: . clamp() returns the given value if in range, else returns the nearest bound. RFC: https://wiki.php.net/rfc/clamp_v2 . stream_last_errors() and stream_clear_errors() RFC: https://wiki.php.net/rfc/stream_errors . stream_socket_get_crypto_status() - URI: . Uri\Rfc3986\Uri::getUriType() and Uri\WhatWg\Url::isSpecialScheme() RFC: https://wiki.php.net/rfc/uri_followup#uri_type_detection . Uri\Rfc3986\Uri::getHostType() and Uri\WhatWg\Url::getHostType() RFC: https://wiki.php.net/rfc/uri_followup#host_type_detection - Zip: . ZipArchive::openString() . ZipArchive::closeString() ======================================== 7. New Classes and Interfaces ======================================== - Date: . Time\Duration RFC: https://wiki.php.net/rfc/duration_class . Time\TimeException RFC: https://wiki.php.net/rfc/duration_class - Intl: . IntlNumberRangeFormatter - OpenSSL: . Openssl\OpensslException . Openssl\Session RFC: https://wiki.php.net/rfc/tls_session_resumption . Openssl\Psk - SNMP: . enum: Snmp\Mib . enum: Snmp\OidOutput . enum: Snmp\Output . enum: Snmp\StringOutput - Standard: . enum SortDirection RFC: https://wiki.php.net/rfc/sort_direction_enum . StreamError . StreamException . enum StreamErrorStore . enum StreamErrorMode . enum StreamErrorCode RFC: https://wiki.php.net/rfc/stream_errors . Io\Poll\Context . Io\Poll\Watcher . enum Io\Poll\Backend . enum Io\Poll\Event . interface Io\Poll\Handle . Io\IoException . Io\Poll\PollException . Io\Poll\FailedPollOperationException . Io\Poll\FailedContextInitializationException . Io\Poll\FailedHandleAddException . Io\Poll\FailedWatcherModificationException . Io\Poll\FailedPollWaitException . Io\Poll\BackendUnavailableException . Io\Poll\InactiveWatcherException . Io\Poll\HandleAlreadyWatchedException . Io\Poll\InvalidHandleException . StreamPollHandle - URI: . Uri\Rfc3986\UriBuilder RFC: https://wiki.php.net/rfc/uri_followup#uri_building ======================================== 8. Removed Extensions and SAPIs ======================================== ======================================== 9. Other Changes to Extensions ======================================== - Hash: . The bundled version of xxHash was upgraded to 0.8.2. - MySQLi: . Added new constant MYSQLI_OPT_COMPRESS. - Opcache: . JIT is now supported for ZTS builds on Apple Silicon. ======================================== 10. New Global Constants ======================================== - Curl: . CURLINFO_SIZE_DELIVERED (libcurl >= 8.20.0). . CURLOPT_SEEKFUNCTION. . CURL_SEEKFUNC_OK. . CURL_SEEKFUNC_FAIL. . CURL_SEEKFUNC_CANTSEEK. . CURL_READFUNC_ABORT. - MySQLi: . MYSQLI_OPT_COMPRESS. - OpenSSL: . OPENSSL_RSA_PSS_SALTLEN_DIGEST. . OPENSSL_RSA_PSS_SALTLEN_AUTO. . OPENSSL_RSA_PSS_SALTLEN_MAX. - Sockets: . TCP_USER_TIMEOUT (Linux only). . AF_UNSPEC. . EAI_BADFLAGS. . EAI_NONAME. . EAI_AGAIN. . EAI_FAIL. . EAI_NODATA. . EAI_FAMILY. . EAI_SOCKTYPE. . EAI_SERVICE. . EAI_ADDRFAMILY. . EAI_SYSTEM. . EAI_OVERFLOW. . EAI_INPROGRESS. . EAI_CANCELED. . EAI_NOTCANCELED. . EAI_ALLDONE. . EAI_INTR. . EAI_IDN_ENCODE. . SO_DETACH_REUSEPORT_BPF (Linux only). - Standard: . ARRAY_FILTER_USE_VALUE. . STREAM_CRYPTO_STATUS_NONE. . STREAM_CRYPTO_STATUS_WANT_READ. . STREAM_CRYPTO_STATUS_WANT_WRITE. ======================================== 11. Changes to INI File Handling ======================================== - Mbstring: . The mbstring.detect_order INI directive now updates the internal detection order when changed at runtime via ini_set(). Previously, runtime changes using ini_set() did not take effect for mb_detect_order(). Setting the directive to NULL or an empty string at runtime now leaves the previously configured detection order unchanged. - MySQLi: . mysqli.default_port now checks the validity of the value which should be between 0 and 65535 inclusive. - Opcache: . opcache.jit_debug accepts a new flag: ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC. When used along with ZEND_JIT_DEBUG_TRACE_EXIT_INFO, the source of exit points is printed in exit info output, in debug builds. ======================================== 12. Windows Support ======================================== - Core: . The official Windows builds now use Visual Studio 2026 (VS18). - LibXML: . The libxml2 library used by the official Windows builds has been upgraded to version 2.15.3. As a result, DOMDocument::$documentURI for documents loaded from a local file now contains a native filesystem path instead of a file URI. - OpenSSL: . The OpenSSL library used by the official Windows builds has been upgraded to OpenSSL 4. ======================================== 13. Other Changes ======================================== - Core: . In case of a hard OOM PHP now calls abort() instead of exit(1), changing the exit code to 134 and possibly creating a core dump. . The PHP_OS_FAMILY constant has an AIX value for when running on AIX or IBM i via PASE. ======================================== 14. Performance Improvements ======================================== - Core: . printf() using only "%s" and "%d" will be compiled into the equivalent string interpolation, avoiding the overhead of a function call and repeatedly parsing the format string. . Arguments are now passed more efficiently to known constructors (e.g. when using new self()). . array_map() using a first-class callable or partial function application callback will be compiled into the equivalent foreach-loop, avoiding the creation of intermediate Closures, the overhead of calling userland callbacks from internal functions and providing for better insight for the JIT. . The performance of the TAILCALL VM has been improved. . The TAILCALL VM is now enabled on Windows when compiling with Clang >= 19 on x86_64. . The performance of ZTS builds has been improved. . Added stateless closure cache. RFC: https://wiki.php.net/rfc/closure-optimizations#stateless_closure_caching - DOM: . Made splitText() faster and consume less memory. - GD: . imagebmp(), imagewbmp(), imagegd(), and imagegd2() now buffer output when writing to PHP streams, significantly improving performance when writing images to files. . Improved performance of imagegrabscreen() and imagegrabwindow() on Windows. - JSON: . Improve performance of encoding arrays and objects. . Improved performance of indentation generation in json_encode() when using PHP_JSON_PRETTY_PRINT. - Intl: . Improved performance of IntlCalendar::getAvailableLocales() and IntlDateFormatter::localtime() / datefmt_localtime() by pre-allocating their returned arrays. . Improved performance of transliterator_list_ids() and resourcebundle_locales() by pre-allocating their returned arrays. - Phar: . Reduced temporary allocations when iterating Phar directories. - Standard: . Improved performance of array_fill_keys(). . Improved performance of array_intersect(). . Improved performance of array_map() with multiple arrays passed. . Improved performance of array_sum() and array_product() for integer-only arrays. . Improved performance of array_unshift(). . Improved performance of array_walk(). . Improved performance of intval('+0b...', 2) and intval('0b...', 2). . Improved performance of str_split(). - URI: . Improved performance of Uri\WhatWg\Url::parse() when collecting validation errors by pre-allocating the error array. . Reduced allocations when reading IPv6/IPvFuture hosts and paths with Uri\Rfc3986\Uri. . Improved performance and memory consumption when using normalizing (non-raw) getters on already-normalized URIs with Uri\Rfc3986\Uri. - Zip: . Improved performance of ZipArchive::addGlob() and ZipArchive::addPattern() by pre-allocating their returned arrays. . Avoid string copies in ZipArchive::addFromString().