PHP 8.6.0 RC3 available for testing

Backward Incompatible Changes

PHP Core

By-reference foreach after array compaction

By-reference foreach loops may now visit previously skipped elements after array compaction. Internal pointers on deleted elements now move to the next surviving element during copy-on-write.

Null coalescing and empty() on magic properties

?? and 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() applied directly to the property is unaffected; nested forms such as isset($o->p['k']) follow the same path as ??.

<?php
#[\AllowDynamicProperties]
class Example
{
    public function __isset(string $name): bool
    {
        $this->$name = 'from __isset()';
        return true;
    }

    public function __get(string $name): string
    {
        return 'from __get()';
    }
}

$example = new Example();
var_dump($example->foo ?? 'default');
// As of PHP 8.6.0: string(14) "from __isset()"
// Prior to PHP 8.6.0: string(12) "from __get()"

String conversion in array_intersect()

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 trimmed by default

Form feed (\f) is now added to the default trimmed characters of trim(), rtrim() and ltrim().

<?php
var_dump(trim("\f hello \f"));
// As of PHP 8.6.0: string(5) "hello"
// Prior to PHP 8.6.0: string(9) "\f hello \f"

New errors for invalid arguments

The following functions now raise a ValueError when an invalid flag or mode value is passed:

The following functions now raise a ValueError when the given argument contains NUL bytes:

The following functions now raise a ValueError for out-of-range values instead of silently clamping them or allowing them to overflow:

  • number_format(), when decimals is outside the integer range.
  • sleep(), when seconds is greater than UINT_MAX, or UINT_MAX / 1000 on Windows.
  • usleep(), when microseconds is greater than UINT_MAX.

linkinfo() now raises a ValueError when the path argument is empty.

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.

The following functions now raise a ValueError when the filename argument contains NUL bytes:

Notice on imprecise number conversion

base_convert(), bindec(), hexdec() and octdec() now raise a notice when they cannot precisely convert the given number.

Endianness modifiers in unpack() format names

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 "s<value" now produce the key "value" instead of "<value", and "C>name" 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 "s1<value". See also the new endianness modifiers.

<?php
var_dump(unpack('s<value', "\x01\x00"));
// As of PHP 8.6.0: ["value" => 1]
// Prior to PHP 8.6.0: ["<value" => 1]

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 read-only (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 class::$prop 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, and raises a ValueError when the integer index is greater than PHP_INT_MAX instead of overflowing to a smaller index.

FTP

ftp_nb_fget(), ftp_nb_fput(), ftp_nb_get() and ftp_nb_put() now throw an Error when the connection is already transferring, instead of emitting a warning and returning false. ftp_close() already throws on the same condition.

GD

imagesetstyle(), imagefilter() and imagecrop() filter the types and values of their array arguments and raise a TypeError or ValueError accordingly.

imageaffinematrixget() now enforces the documented array|float type for the options parameter, including the corresponding weak and strict typing behavior.

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

The message of the DivisionByZeroError raised by gmp_powm() on modulo by zero now includes the function name and argument index (modulus).

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 MessageFormatter::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 locale instead of the malformed without fallback from to locale.

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 an IntlException. Previously, these paths emitted a warning and compared the value as an empty string.

MBString

Unicode data tables have been updated to Unicode 18.0.

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 the other preg_* functions.

PGSQL

When pg_fetch_object() is given a non-empty constructor_args for a class without a constructor, the ValueError now refers to 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. Non-magic names that merely share the ".phar" prefix are now treated 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".

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.

session_module_name() now throws a ValueError if name is a string containing NUL bytes.

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 SessionUpdateTimestampHandlerInterface::updateTimestamp() instead of SessionHandlerInterface::write(). Previously, SessionHandlerInterface::write() was always called for empty sessions because session_encode() returned false, bypassing the lazy_write comparison. Custom session handlers that rely on SessionHandlerInterface::write() being called with empty data (e.g. to destroy the session) should implement the same logic in their SessionUpdateTimestampHandlerInterface::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 SessionUpdateTimestampHandlerInterface::validateId() and SessionIdInterface::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).

SessionHandler::validateId() has been added and delegates to the configured save handler. A subclass that declares SessionHandler::validateId() without a return type now emits a deprecation notice for the tentative bool return type. A subclass that overrides SessionHandler::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 a TypeError for non-array "classmap" options and a 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 a ValueError instead of a 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 SplFileObject::current() call has cached a line. A subsequent SplFileObject::current() call returns the new line rather than the previous one.

SplFileObject::fgets() no longer caches the returned line for subsequent SplFileObject::current() calls. SplFileObject::current() now re-reads from the current stream position instead of returning the line SplFileObject::fgets() just returned.

SplFileObject::next() past EOF no longer increments SplFileObject::key() without bound. SplFileObject::seek() past EOF now produces the same SplFileObject::key() value as SplTempFileObject; the two previously returned different values.

DirectoryIterator::key() now returns int|string, and DirectoryIterator::current() returns string|SplFileInfo|static.

Sysvshm

shm_attach() 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.

URI

Uri\WhatWg\Url::__construct() now sets softErrors to an empty array when URL processing throws an exception, instead of preserving its value. URL validation errors remain available in the Uri\WhatWg\InvalidUrlException::$errors property.

Uri\WhatWg\Url::__construct(), Uri\WhatWg\Url::parse(), the Uri\WhatWg\Url::with*() methods, and Uri\WhatWg\UrlBuilder::build() now report validation errors in the order in which they are detected. This reverses the order of multiple errors compared to PHP 8.5.

Zip

ZipArchive::extractTo() now raises a TypeError for the files argument if one or more of the entries is not a string.

ZipArchive::addGlob() and ZipArchive::addPattern() now raise a TypeError when the "remove_all_path" option is not of type bool, or when the "comp_method", "comp_flags", or "enc_method" options are not of type int (numeric strings are coerced), instead of emitting a warning.

Serializing or unserializing a ZipArchive now throws an Exception. A subclass can override __serialize() and __unserialize() to round-trip through ZipArchive::closeString() and ZipArchive::openString().

Zlib

deflate_init() now raises a TypeError when the value for option "level", "memory", "window", or "strategy" is not of type int.

inflate_init() now raises a TypeError when the value for option "window" is not of type int.

+添加备注

用户贡献的备注

此页面尚无用户贡献的备注。
To Top