Backward Incompatible Changes
PHP Core
"array" and "callable" alias name
It is no longer possible to use "array"
and "callable" as class alias names
in class_alias()
Loosely comparing uncomparable objects
Loosely comparing uncomparable objects (e.g. enums,
CurlHandle and other internal classes) to booleans
was previously inconsistent. If compared to a boolean literal
$object == true, it would behave the same way as
(bool)$object. If compared to a statically unknown value
$object == $true, it would always return false.
This behavior was consolidated to always follow the behavior of
(bool)$object.
Return value of gc_collect_cycles
The return value of gc_collect_cycles() no longer includes
strings and resources that were indirectly collected through cycles.
Substitute static keyword in final subclass
It is now allowed to substitute static with self or the concrete class name
in final subclasses.
Tick handlers
The tick handlers are now deactivated after all shutdown functions,
destructors have run and the output handlers have been cleaned up.
Traits binding
Traits are now bound before the parent class. This is a subtle behavioral
change, but should more closely match user expectations.
Errors during compilation and class linking
Errors emitted during compilation and class linking are now always delayed
and handled after compilation or class linking. Fatal errors emitted during
compilation or class linking cause any delayed errors to be handled
immediately, without calling user-defined error handlers.
Exceptions thrown by user-defined error handler
Exceptions thrown by user-defined error handlers when handling class linking
errors are not promoted to fatal errors anymore and do not prevent linking.
Attribute apply error during compilation
Applying #[\Attribute] to an abstract class, enum, interface, or trait
triggers an error during compilation. Previously, the attribute could be
added, but when ReflectionAttribute::newInstance()
was called an error would be thrown.
The error can be delayed from compilation to runtime using the new
#[\DelayedTargetValidation] attribute.
disable_classes INI setting
The disable_classes INI setting
has been removed as it causes various engine assumptions to be broken.
Destructuring non-array values
Destructuring non-array values (other than null) using [] or list() now
emits a warning.
MBString
Unicode data tables have been updated to Unicode 17.0
MySQLi
Calling the mysqli constructor on an already-constructed object
is now no longer possible and throws an Error.
ODBC
ODBC now assumes that at least ODBC 3.5 functionality is available.
The ODBCVER definition and build system flags to control it have been removed.
ODBC no longer has build flags to build against specific drivers (except
for DB2) and removes special cases for those drivers. It is strongly
recommended to use a driver manager like iODBC or unixODBC on non-Windows.
Opcache
The Opcache extension is now always built into the PHP binary and is always
loaded.
The INI directives opcache.enable
and opcache.enable_cli are still
honored.
The --enable-opcache/--disable-opcache
configure flags have been removed, and the build does not produce opcache.so
or php_opcache.dll objects anymore.
Using zend_extension=opcache.so or
zend_extension=php_opcache.dll INI directives
will emit a warning.
PCRE
The extension is compiled without semi-deprecated
PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK compile option.
PDO
The constructor arguments set in conjunction with
PDO::FETCH_CLASS now follow the usual CUFA
(call_user_func_array()) semantics.
This means string keys will act like a named argument.
Moreover, automatic wrapping for by-value arguments passed to a by-ref
parameter has been removed, and the usual E_WARNING
about this is now emitted.
To pass a variable by-ref to a constructor argument use the general
array value reference assignment: $ctor_args = [&$valByRef]
Attempting to call PDOStatement::setFetchMode() during
a call to PDOStatement::fetch(),
PDOStatement::fetchObject(),
PDOStatement::fetchAll(), for example using tricks such as
passing the statement object as a constructor argument when fetching into an
object, will now throw an Error.
The value of the constants PDO::FETCH_GROUP,
PDO::FETCH_UNIQUE,
PDO::FETCH_CLASSTYPE,
PDO::FETCH_PROPS_LATE, and
PDO::FETCH_SERIALIZE have changed.
A ValueError is now thrown if
PDO::FETCH_PROPS_LATE is used with a fetch mode
different than PDO::FETCH_CLASS, consistent with
other fetch flags.
A ValueError is now thrown if
PDO::FETCH_INTO is used as a fetch mode in
PDOStatement::fetchAll(),
similar to PDO::FETCH_LAZY.
PDO_FIREBIRD
A ValueError is now thrown when trying to set a cursor
name that is too long on a PDOStatement resulting from
the Firebird driver.
POSIX
posix_kill() now throws a
ValueError when the process_id argument is
lower or greater than what the platform supports (signed integer or
long range), posix_setpgid() now throws a
ValueError when the process_id or
the process_group_id is lower than zero or greater than what the platform
supports.
posix_setrlimit() now throws a
ValueError when the hard_limit or
soft_limit arguments are lower than -1 or if soft_limit is greater than
hard_limit.
Reflection
ReflectionAttribute::newInstance() can now throw
errors for internal attributes if the attribute was applied on an invalid
target and the error was delayed from compile time to runtime via the
#[\DelayedTargetValidation] attribute.
Session
Attempting to write session data where $_SESSION has a key
containing the pipe character (|) will now emit a warning
instead of silently failing.
session_start() is stricter in regard to the options
argument. It now throws a ValueError if
the array is not a hashmap, or a TypeError
if the read_and_close value is not a valid type compatible with int.
SimpleXML
Passing an XPath expression that returns something other than a node set
to SimpleXMLElement::xpath() will now emit a warning
and return false, instead of silently failing and returning an empty array.
SPL
ArrayObject no longer accepts enums, as modifying the
$name or $value properties can break
engine assumptions.
SplFileObject::fwrite()'s parameter
length is now nullable.
The default value changed from 0 to null.
Standard
Using a printf-family function with a formatter that did not specify the
precision previously incorrectly reset the precision instead of treating
it as a precision of 0.
Passing an integer 0 as the locales
argument to setlocale() is no longer supported and now throws
a TypeError.