PHP 8.2

Backward Incompatible Changes

Date

DateTime::createFromImmutable() now has a tentative return type of static, previously it was DateTime.

DateTimeImmutable::createFromMutable() now has a tentative return type of static, previously it was DateTimeImmutable.

ODBC

The ODBC extension now escapes the username and password for the case when both a connection string and username/password are passed, and the string must be appended to. Before, user values containing values needing escaping could have created a malformed connection string, or injected values from user-provided data. The escaping rules should be identical to the .NET BCL DbConnectionOptions behaviour.

PDO_ODBC

The PDO_ODBC extension also escapes the username and password when a connection string is passed. See the change to the ODBC extension for further details.

Standard

glob() now returns an empty array if all paths are restricted by open_basedir. Previously it returned false. Moreover, a warning is now emitted even if only some paths are restricted by open_basedir.

FilesystemIterator::__construct(): prior to PHP 8.2.0, FilesystemIterator::SKIP_DOTS constant was always set and couldn't be disabled. In order to maintain the previous behaviour the constant must be explicitly set when using the flags parameter. The default value from flags parameter has not been modified.

strtolower(), strtoupper(), stristr(), stripos(), strripos(), lcfirst(), ucfirst(), ucwords(), and str_ireplace() are no longer locale-sensitive. They now perform ASCII case conversion, as if the locale were "C". Localized versions of these functions are available in the MBString extension. Moreover, array_change_key_case(), and sorting with SORT_FLAG_CASE now also use ASCII case conversion.

str_split() returns an empty array for an empty string now. Previously it returned an array with a single empty string entry. mb_str_split() is not affected by this change as it was already behaving like that.

ksort() and krsort() now do numeric string comparison under SORT_REGULAR using the standard PHP 8 rules now.

Standard PHP Library (SPL)

The following methods now enforce their signature:

SplFileObject::hasChildren() now has a tentative return type of false, previously it was bool.

SplFileObject::getChildren() now has a tentative return type of null, previously it was ?RecursiveIterator.

GlobIterator now returns an empty array if all paths are restricted by open_basedir. Previously it returned false. Moreover, a warning is now emitted even if only some paths are restricted by open_basedir.

PHP 8.1

Backward Incompatible Changes

PHP Core

$GLOBALS Access Restrictions

Access to the $GLOBALS array is now subject to a number of restrictions. Read and write access to individual array elements like $GLOBALS['var'] continues to work as-is. Read-only access to the entire $GLOBALS array also continues to be supported. However, write access to the entire $GLOBALS array is no longer supported. For example, array_pop($GLOBALS) will result in an error.

Usage of static Variables in Inherited Methods

When a method using static variables is inherited (but not overridden), the inherited method will now share static variables with the parent method.

<?php
class {
    public static function 
counter() {
        static 
$counter 0;
        
$counter++;
        return 
$counter;
    }
}
class 
extends {}
var_dump(A::counter()); // int(1)
var_dump(A::counter()); // int(2)
var_dump(B::counter()); // int(3), previously int(1)
var_dump(B::counter()); // int(4), previously int(2)
?>
This means that static variables in methods now behave the same way as static properties.

Optional parameters specified before required parameters

An optional parameter specified before required parameters is now always treated as required, even when called using named arguments. As of PHP 8.0.0, but prior to PHP 8.1.0, the below emits a deprecation notice on the definition, but runs successfully when called. As of PHP 8.1.0, an error of class ArgumentCountError is thrown, as it would be when called with positional arguments.

<?php
function makeyogurt($container "bowl"$flavour)
{
    return 
"Making a $container of $flavour yogurt.\n";
}
try
{
    echo 
makeyogurt(flavour"raspberry");
}
catch (
Error $e)
{
    echo 
get_class($e), ' - '$e->getMessage(), "\n";
}
?>

Output of the above example in PHP 8.0:

Deprecated: Required parameter $flavour follows optional parameter $container
 in example.php on line 3
Making a bowl of raspberry yogurt.

Output of the above example in PHP 8.1:

Deprecated: Optional parameter $container declared before required parameter
 $flavour is implicitly treated as a required parameter in example.php on line 3
ArgumentCountError - makeyogurt(): Argument #1 ($container) not passed

Note that a default value of null can be used before required parameters to specify a nullable type, but the parameter will still be required.

Return Type Compatibility with Internal Classes

Most non-final internal methods now require overriding methods to declare a compatible return type, otherwise a deprecated notice is emitted during inheritance validation. In case the return type cannot be declared for an overriding method due to PHP cross-version compatibility concerns, a #[ReturnTypeWillChange] attribute can be added to silence the deprecation notice.

New Keywords

readonly is a keyword now. However, it still may be used as function name.

never is now a reserved word, so it cannot be used to name a class, interface or trait, and is also prohibited from being used in namespaces.

Resource to Object Migration

Several resources have been migrated to objects. Return value checks using is_resource() should be replaced with checks for false.

MySQLi

mysqli_fetch_fields(), and mysqli_fetch_field_direct() will now always return 0 for the max_length. This information can be computed by iterating over the result set, and taking the maximum length. This is what PHP was doing internally previously.

The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has any effect.

The MYSQLI_STORE_RESULT_COPY_DATA option no longer has any effect. Passing any value to the mode parameter of mysqli::store_result() no longer has any effect.

mysqli::connect() now returns true instead of null on success.

The default error handling mode has been changed from "silent" to "exceptions" See the MySQLi reporting mode page for more details on what this entails, and how to explicitly set this attribute. To restore the previous behaviour use: mysqli_report(MYSQLI_REPORT_OFF);

Classes extending mysqli_stmt::execute() are now required to specify the additional optional parameter.

MySQLnd

The mysqlnd.fetch_data_copy INI directive has been removed. This should not result in user-visible behavior changes.

OpenSSL

EC private keys will now be exported in PKCS#8 format rather than traditional format, just like all other keys.

openssl_pkcs7_encrypt() and openssl_cms_encrypt() will now to default using AES-128-CBC rather than RC2-40. The RC2-40 cipher is considered insecure and not enabled by default by OpenSSL 3.

PHP Data Objects

PDO::ATTR_STRINGIFY_FETCHES now stringifies values of type bool to "0" or "1". Previously bools were not stringified.

Calling PDOStatement::bindColumn() with PDO::PARAM_LOB will now constantly bind a stream result when PDO::ATTR_STRINGIFY_FETCHES is not enabled. Previously, the result would either be a stream or a string depending on the used database driver and the time the binding is performed.

MySQL Driver

Integers and floats in result sets will now be returned using native PHP types instead of strings when using emulated prepared statements. This matches the behavior of native prepared statements. The previous behaviour can be restored by enabling the PDO::ATTR_STRINGIFY_FETCHES option.

SQLite Driver

Integers and floats in results sets will now be returned using native PHP types. The previous behaviour can be restored by enabling the PDO::ATTR_STRINGIFY_FETCHES option.

Phar

To comply with the ArrayAccess interface, Phar::offsetUnset() and PharData::offsetUnset() no longer return a bool.

Standard

version_compare() no longer accepts undocumented operator abbreviations.

htmlspecialchars(), htmlentities(), htmlspecialchars_decode(), html_entity_decode(), and get_html_translation_table() now use ENT_QUOTES | ENT_SUBSTITUTE rather than ENT_COMPAT by default. This means that ' is escaped to &#039; while previously nothing was done. Additionally, malformed UTF-8 will be replaced by a Unicode substitution character, instead of resulting in an empty string.

debug_zval_dump() now prints the refcount of a reference wrappers with their refcount, instead of only prepending & to the value. This more accurately models reference representation since PHP 7.0.

debug_zval_dump() now prints interned instead of a dummy refcount for interned strings and immutable arrays.

Standard PHP Library (SPL)

SplFixedArray, will now be JSON encoded like an array

PHP 8.0

Backward Incompatible Changes

PHP Core

String to Number Comparison

Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings. Comparisons between numbers and numeric strings continue to work as before. Notably, this means that 0 == "not-a-number" is considered false now.

Comparison Before After
0 == "0" true true
0 == "0.0" true true
0 == "foo" true false
0 == "" true false
42 == " 42" true true
42 == "42foo" true false

Other incompatible Changes

  • match is now a reserved keyword.

  • mixed is now a reserved word, so it cannot be used to name a class, interface or trait, and is also prohibited from being used in namespaces.

  • Assertion failures now throw by default. If the old behavior is desired, assert.exception=0 can be set in the INI settings.

  • Methods with the same name as the class are no longer interpreted as constructors. The __construct() method should be used instead.

  • The ability to call non-static methods statically has been removed. Thus is_callable() will fail when checking for a non-static method with a classname (must check with an object instance).

  • The (real) and (unset) casts have been removed.

  • The track_errors ini directive has been removed. This means that php_errormsg is no longer available. The error_get_last() function may be used instead.

  • The ability to define case-insensitive constants has been removed. The third argument to define() may no longer be true.

  • The ability to specify an autoloader using an __autoload() function has been removed. spl_autoload_register() should be used instead.

  • The errcontext argument will no longer be passed to custom error handlers set with set_error_handler().

  • create_function() has been removed. Anonymous functions may be used instead.

  • each() has been removed. foreach or ArrayIterator should be used instead.

  • The ability to unbind this from closures that were created from a method, using Closure::fromCallable() or ReflectionMethod::getClosure(), has been removed.

  • The ability to unbind this from proper closures that contain uses of this has also been removed.

  • The ability to use array_key_exists() with objects has been removed. isset() or property_exists() may be used instead.

  • The behavior of array_key_exists() regarding the type of the key parameter has been made consistent with isset() and normal array access. All key types now use the usual coercions and array/object keys throw a TypeError.

  • Any array that has a number n as its first numeric key will use n+1 for its next implicit key, even if n is negative.

  • The default error_reporting level is now E_ALL. Previously it excluded E_NOTICE and E_DEPRECATED.

  • display_startup_errors is now enabled by default.

  • Using parent inside a class that has no parent will now result in a fatal compile-time error.

  • The @ operator will no longer silence fatal errors (E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_PARSE). Error handlers that expect error_reporting to be 0 when @ is used, should be adjusted to use a mask check instead:

    <?php
    // Replace
    function my_error_handler($err_no$err_msg$filename$linenum) {
        if (
    error_reporting() == 0) {
            return 
    false;
        }
        
    // ...
    }

    // With
    function my_error_handler($err_no$err_msg$filename$linenum) {
        if (!(
    error_reporting() & $err_no)) {
            return 
    false;
        }
        
    // ...
    }
    ?>

    Additionally, care should be taken that error messages are not displayed in production environments, which can result in information leaks. Please ensure that display_errors=Off is used in conjunction with error logging.

  • #[ is no longer interpreted as the start of a comment, as this syntax is now used for attributes.

  • Inheritance errors due to incompatible method signatures (LSP violations) will now always generate a fatal error. Previously a warning was generated in some cases.

  • The precedence of the concatenation operator has changed relative to bitshifts and addition as well as subtraction.

    <?php
    echo "Sum: " $a $b;
    // was previously interpreted as:
    echo ("Sum: " $a) + $b;
    // is now interpreted as:
    echo "Sum:" . ($a $b);
    ?>
  • Arguments with a default value that resolves to null at runtime will no longer implicitly mark the argument type as nullable. Either an explicit nullable type, or an explicit null default value has to be used instead.

    <?php
    // Replace
    function test(int $arg CONST_RESOLVING_TO_NULL) {}
    // With
    function test(?int $arg CONST_RESOLVING_TO_NULL) {}
    // Or
    function test(int $arg null) {}
    ?>
  • A number of warnings have been converted into Error exceptions:

    • Attempting to write to a property of a non-object. Previously this implicitly created an stdClass object for null, false and empty strings.
    • Attempting to append an element to an array for which the PHP_INT_MAX key is already used.
    • Attempting to use an invalid type (array or object) as an array key or string offset.
    • Attempting to write to an array index of a scalar value.
    • Attempting to unpack a non-array/Traversable.
    • Attempting to access unqualified constants which are undefined. Previously, unqualified constant accesses resulted in a warning and were interpreted as strings.

    A number of notices have been converted into warnings:

    • Attempting to read an undefined variable.
    • Attempting to read an undefined property.
    • Attempting to read an undefined array key.
    • Attempting to read a property of a non-object.
    • Attempting to access an array index of a non-array.
    • Attempting to convert an array to string.
    • Attempting to use a resource as an array key.
    • Attempting to use null, a boolean, or a float as a string offset.
    • Attempting to read an out-of-bounds string offset.
    • Attempting to assign an empty string to a string offset.
  • Attempting to assign multiple bytes to a string offset will now emit a warning.

  • Unexpected characters in source files (such as NUL bytes outside of strings) will now result in a ParseError exception instead of a compile warning.

  • Uncaught exceptions now go through "clean shutdown", which means that destructors will be called after an uncaught exception.

  • The compile time fatal error "Only variables can be passed by reference" has been delayed until runtime, and converted into an "Argument cannot be passed by reference" Error exception.

  • Some "Only variables should be passed by reference" notices have been converted to "Argument cannot be passed by reference" exception.

  • The generated name for anonymous classes has changed. It will now include the name of the first parent or interface:

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

    The name shown above is still followed by a NUL byte and a unique suffix.

  • Non-absolute trait method references in trait alias adaptations are now required to be unambiguous:

    <?php
    class {
        use 
    T1T2 {
            
    func as otherFunc;
        }
        function 
    func() {}
    }
    ?>

    If both T1::func() and T2::func() exist, this code was previously silently accepted, and func was assumed to refer to T1::func. Now it will generate a fatal error instead, and either T1::func or T2::func needs to be written explicitly.

  • The signature of abstract methods defined in traits is now checked against the implementing class method:

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

    class 
    MyClass {
        use 
    MyTrait;

        
    // Error, because of return type mismatch.
        
    private function neededByTrait(): int { return 42; }
    }
    ?>
  • Disabled functions are now treated exactly like non-existent functions. Calling a disabled function will report it as unknown, and redefining a disabled function is now possible.

  • data:// stream wrappers are no longer writable, which matches the documented behavior.

  • The arithmetic and bitwise operators +, -, *, /, **, %, <<, >>, &, |, ^, ~, ++, -- will now consistently throw a TypeError when one of the operands is an array, resource or non-overloaded object. The only exception to this is the array + array merge operation, which remains supported.

  • Float to string casting will now always behave locale-independently.

    <?php
    setlocale
    (LC_ALL"de_DE");
    $f 3.14;
    echo 
    $f"\n";
    // Previously: 3,14
    // Now:        3.14
    ?>

    See printf(), number_format() and NumberFormatter() for ways to customize number formatting.

  • Support for deprecated curly braces for offset access has been removed.

    <?php
    // Instead of:
    $array{0};
    $array{"key"};
    // Write:
    $array[0];
    $array["key"];
    ?>
  • Applying the final modifier on a private method will now produce a warning unless that method is the constructor.

  • If an object constructor exit()s, the object destructor will no longer be called. This matches the behavior when the constructor throws.

  • Namespaced names can no longer contain whitespace: While Foo\Bar will be recognized as a namespaced name, Foo \ Bar will not. Conversely, reserved keywords are now permitted as namespace segments, which may also change the interpretation of code: new\x is now the same as constant('new\x'), not new \x().

  • Nested ternaries now require explicit parentheses.

  • debug_backtrace() and Exception::getTrace() will no longer provide references to arguments. It will not be possible to change function arguments through the backtrace.

  • Numeric string handling has been altered to be more intuitive and less error-prone. Trailing whitespace is now allowed in numeric strings for consistency with how leading whitespace is treated. This mostly affects:

    • The is_numeric() function
    • String-to-string comparisons
    • Type declarations
    • Increment and decrement operations

    The concept of a "leading-numeric string" has been mostly dropped; the cases where this remains exist in order to ease migration. Strings which emitted an E_NOTICE "A non well-formed numeric value encountered" will now emit an E_WARNING "A non-numeric value encountered" and all strings which emitted an E_WARNING "A non-numeric value encountered" will now throw a TypeError. This mostly affects:

    • Arithmetic operations
    • Bitwise operations

    This E_WARNING to TypeError change also affects the E_WARNING "Illegal string offset 'string'" for illegal string offsets. The behavior of explicit casts to int/float from strings has not been changed.

  • Magic Methods will now have their arguments and return types checked if they have them declared. The signatures should match the following list:

    • __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() array keys will now be interpreted as parameter names, instead of being silently ignored.

  • Declaring a function called assert() inside a namespace is no longer allowed, and issues E_COMPILE_ERROR. The assert() function is subject to special handling by the engine, which may lead to inconsistent behavior when defining a namespaced function with the same name.

Resource to Object Migration

Several resources have been migrated to objects. Return value checks using is_resource() should be replaced with checks for false.

COM and .Net (Windows)

The ability to import case-insensitive constants from type libraries has been removed. The second argument to com_load_typelib() may no longer be false; com.autoregister_casesensitive may no longer be disabled; case-insensitive markers in com.typelib_file are ignored.

CURL

CURLOPT_POSTFIELDS no longer accepts objects as arrays. To interpret an object as an array, perform an explicit (array) cast. The same applies to other options accepting arrays as well.

Date and Time

mktime() and gmmktime() now require at least one argument. time() can be used to get the current timestamp.

DOM

Unimplemented classes from the DOM extension that had no behavior and contained test data have been removed. These classes have also been removed in the latest version of the DOM standard:

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

Unimplemented methods from the DOM extension that had no behavior have been removed:

  • 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() has been removed; exif_read_data() should be used instead.

Filter

  • The FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED flags for the FILTER_VALIDATE_URL filter have been removed. The scheme and host are (and have been) always required.

  • The INPUT_REQUEST and INPUT_SESSION source for filter_input() etc. have been removed. These were never implemented and their use always generated a warning.

GD

  • The deprecated function image2wbmp() has been removed.

  • The deprecated functions png2wbmp() and jpeg2wbmp() have been removed.

  • The default mode parameter of imagecropauto() no longer accepts -1. IMG_CROP_DEFAULT should be used instead.

  • On Windows, php_gd2.dll has been renamed to php_gd.dll.

GMP

gmp_random() has been removed. One of gmp_random_range() or gmp_random_bits() should be used instead.

Iconv

iconv implementations which do not properly set errno in case of errors are no longer supported.

IMAP

Internationalization Functions

  • The deprecated constant INTL_IDNA_VARIANT_2003 has been removed.

  • The deprecated Normalizer::NONE constant has been removed.

LDAP

MBString

OCI8

  • The OCI-Lob class is now called OCILob, and the OCI-Collection class is now called OCICollection for name compliance enforced by PHP 8 arginfo type annotation tooling.

  • Several alias functions have been marked as deprecated.

  • oci_internal_debug() and its alias ociinternaldebug() have been removed.

ODBC

OpenSSL

Regular Expressions (Perl-Compatible)

When passing invalid escape sequences they are no longer interpreted as literals. This behavior previously required the X modifier – which is now ignored.

PHP Data Objects

  • The default error handling mode has been changed from "silent" to "exceptions". See Errors and error handling for details.

  • The signatures of some PDO methods have changed:

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

PDO ODBC

The php.ini directive pdo_odbc.db2_instance_name has been removed.

PDO MySQL

PDO::inTransaction() now reports the actual transaction state of the connection, rather than an approximation maintained by PDO. If a query that is subject to "implicit commit" is executed, PDO::inTransaction() will subsequently return false, as a transaction is no longer active.

PostgreSQL

  • The deprecated pg_connect() syntax using multiple parameters instead of a connection string is no longer supported.

  • The deprecated pg_lo_import() and pg_lo_export() signature that passes the connection as the last argument is no longer supported. The connection should be passed as first argument instead.

  • pg_fetch_all() will now return an empty array instead of false for result sets with zero rows.

Phar

Metadata associated with a phar will no longer be automatically unserialized, to fix potential security vulnerabilities due to object instantiation, autoloading, etc.

Reflection

  • The method signatures

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

    have been changed to:

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

    Code that must be compatible with both PHP 7 and PHP 8 can use the following signatures to be compatible with both versions:

    • ReflectionClass::newInstance($arg = null, ...$args)
    • ReflectionFunction::invoke($arg = null, ...$args)
    • ReflectionMethod::invoke($object, $arg = null, ...$args)
  • The ReflectionType::__toString() method will now return a complete debug representation of the type, and is no longer deprecated. In particular the result will include a nullability indicator for nullable types. The format of the return value is not stable and may change between PHP versions.

  • Reflection export() methods have been removed. Instead reflection objects can be cast to string.

  • ReflectionMethod::isConstructor() and ReflectionMethod::isDestructor() now also return true for __construct() and __destruct() methods of interfaces. Previously, this would only be true for methods of classes and traits.

  • ReflectionType::isBuiltin() method has been moved to ReflectionNamedType. ReflectionUnionType does not have it.

Sockets

  • The deprecated AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES flags for socket_addrinfo_lookup() have been removed.

Standard PHP Library (SPL)

Standard Library

  • assert() will no longer evaluate string arguments, instead they will be treated like any other argument. assert($a == $b) should be used instead of assert('$a == $b'). The assert.quiet_eval ini directive and the ASSERT_QUIET_EVAL constant have also been removed, as they would no longer have any effect.

  • parse_str() can no longer be used without specifying a result array.

  • The string.strip_tags filter has been removed.

  • The needle argument of strpos(), strrpos(), stripos(), strripos(), strstr(), strchr(), strrchr(), and stristr() will now always be interpreted as a string. Previously non-string needles were interpreted as an ASCII code point. An explicit call to chr() can be used to restore the previous behavior.

  • The needle argument for strpos(), strrpos(), stripos(), strripos(), strstr(), stristr() and strrchr() can now be empty.

  • The length argument for substr(), substr_count(), substr_compare(), and iconv_substr() can now be null. null values will behave as if no length argument was provided and will therefore return the remainder of the string instead of an empty string.

  • The length argument for array_splice() can now be null. null values will behave identically to omitting the argument, thus removing everything from the offset to the end of the array.

  • The args argument of vsprintf(), vfprintf(), and vprintf() must now be an array. Previously any type was accepted.

  • The 'salt' option of password_hash() is no longer supported. If the 'salt' option is used a warning is generated, the provided salt is ignored, and a generated salt is used instead.

  • The quotemeta() function will now return an empty string if an empty string was passed. Previously false was returned.

  • The following functions have been removed:

  • FILTER_SANITIZE_MAGIC_QUOTES has been removed.

  • Calling implode() with parameters in a reverse order ($pieces, $glue) is no longer supported.

  • parse_url() will now distinguish absent and empty queries and fragments:

    • 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 = ""
    Previously all cases resulted in query and fragment being null.
  • var_dump() and debug_zval_dump() will now print floating-point numbers using serialize_precision rather than precision. In a default configuration, this means that floating-point numbers are now printed with full accuracy by these debugging functions.

  • If the array returned by __sleep() contains non-existing properties, these are now silently ignored. Previously, such properties would have been serialized as if they had the value null.

  • The default locale on startup is now always "C". No locales are inherited from the environment by default. Previously, LC_ALL was set to "C", while LC_CTYPE was inherited from the environment. However, some functions did not respect the inherited locale without an explicit setlocale() call. An explicit setlocale() call is now always required if a locale component should be changed from the default.

  • The deprecated DES fallback in crypt() has been removed. If an unknown salt format is passed to crypt(), the function will fail with *0 instead of falling back to a weak DES hash now.

  • Specifying out of range rounds for SHA256/SHA512 crypt() will now fail with *0 instead of clamping to the closest limit. This matches glibc behavior.

  • The result of sorting functions may have changed, if the array contains elements that compare as equal.

  • Any functions accepting callbacks that are not explicitly specified to accept parameters by reference will now warn if a callback with reference parameters is used. Examples include array_filter() and array_reduce(). This was already the case for most, but not all, functions previously.

  • The HTTP stream wrapper as used by functions like file_get_contents() now advertises HTTP/1.1 rather than HTTP/1.0 by default. This does not change the behavior of the client, but may cause servers to respond differently. To retain the old behavior, set the 'protocol_version' stream context option, e.g.

    <?php
    $ctx 
    stream_context_create(['http' => ['protocol_version' => '1.0']]);
    echo 
    file_get_contents('http://example.org'false$ctx);
    ?>
  • Calling crypt() without an explicit salt is no longer supported. If you would like to produce a strong hash with an auto-generated salt, use password_hash() instead.

  • substr(), mb_substr(), iconv_substr() and grapheme_substr() now consistently clamp out-of-bounds offsets to the string boundary. Previously, false was returned instead of the empty string in some cases.

  • On Windows, the program execution functions (proc_open(), exec(), popen() etc.) using the shell, now consistently execute %comspec% /s /c "$commandline", which has the same effect as executing $commandline (without additional quotes).

Sysvsem

  • The auto_release parameter of sem_get() was changed to accept bool values rather than int.

Tidy

Tokenizer

  • T_COMMENT tokens will no longer include a trailing newline. The newline will instead be part of a following T_WHITESPACE token. It should be noted that T_COMMENT is not always followed by whitespace, it may also be followed by T_CLOSE_TAG or end-of-file.

  • Namespaced names are now represented using the T_NAME_QUALIFIED (Foo\Bar), T_NAME_FULLY_QUALIFIED (\Foo\Bar) and T_NAME_RELATIVE (namespace\Foo\Bar) tokens. T_NS_SEPARATOR is only used for standalone namespace separators, and only syntactially valid in conjunction with group use declarations.

XMLReader

XMLReader::open() and XMLReader::xml() are now static methods. They can still be called as instance methods, but inheriting classes need to declare them as static if they override these methods.

XML-RPC

The XML-RPC extension has been moved to PECL and is no longer part of the PHP distribution.

Zip

ZipArchive::OPSYS_Z_CPM has been removed (this name was a typo). Use ZipArchive::OPSYS_CPM instead.

Zlib

Windows PHP Test Packs

The test runner has been renamed from run-test.php to run-tests.php, to match its name in php-src.

PHP 7.4

Backward Incompatible Changes

PHP Core

Array-style access of non-arrays

Trying to use values of type null, bool, int, float or resource as an array (such as $null["key"]) will now generate a notice.

get_declared_classes() function

The get_declared_classes() function no longer returns anonymous classes that have not been instantiated yet.

fn keyword

fn is now a reserved keyword. In particular, it can no longer be used as a function or class name. It can still be used as a method or class constant name.

<?php tag at end of file

<?php at the end of the file (without trailing newline) will now be interpreted as an opening PHP tag. Previously it was interpreted either as a short opening tag followed by literal php and resulted in a syntax error (with short_open_tag=1) or was interpreted as a literal <?php string (with short_open_tag=0).

Stream wrappers

When using include/require on a stream, streamWrapper::stream_set_option() will be invoked with the STREAM_OPTION_READ_BUFFER option. Custom stream wrapper implementations may need to implement the streamWrapper::stream_set_option() method to avoid a warning (always returning false is a sufficient implementation).

Serialization

The o serialization format has been removed. As it is never produced by PHP, this may only break unserialization of manually crafted strings.

Password algorithm constants

Password hashing algorithm identifiers are now nullable strings rather than integers.

  • PASSWORD_DEFAULT was int 1; now is string '2y' (in PHP 7.4.0, 7.4.1, and 7.4.2 it was null)
  • PASSWORD_BCRYPT was int 1; now is string '2y'
  • PASSWORD_ARGON2I was int 2; now is string 'argon2i'
  • PASSWORD_ARGON2ID was int 3; now is string 'argon2id'

Applications correctly using the constants PASSWORD_DEFAULT, PASSWORD_BCRYPT, PASSWORD_ARGON2I, and PASSWORD_ARGON2ID will continue to function correctly.

htmlentities() function

htmlentities() will now raise a notice (instead of a strict standards warning) if it is used with an encoding for which only basic entity substitution is supported, in which case it is equivalent to htmlspecialchars().

fread() and fwrite() function

fread() and fwrite() will now return false if the operation failed. Previously an empty string or 0 was returned. EAGAIN/EWOULDBLOCK are not considered failures.

These functions now also raise a notice on failure, such as when trying to write to a read-only file resource.

BCMath Arbitrary Precision Mathematics

BCMath functions will now warn if a non well-formed number is passed, such as "32foo". The argument will be interpreted as zero, as before.

CURL

Attempting to serialize a CURLFile class will now generate an exception. Previously the exception was only thrown on unserialization.

Using CURLPIPE_HTTP1 is deprecated, and is no longer supported as of cURL 7.62.0.

The $version parameter of curl_version() is deprecated. If any value not equal to the default CURLVERSION_NOW is passed, a warning is raised and the parameter is ignored.

Date and Time

Calling var_dump() or similar on a DateTime or DateTimeImmutable instance will no longer leave behind accessible properties on the object.

Comparison of DateInterval objects (using ==, <, and so on) will now generate a warning and always return false. Previously all DateInterval objects were considered equal, unless they had properties.

Intl

The default parameter value of idn_to_ascii() and idn_to_utf8() is now INTL_IDNA_VARIANT_UTS46 instead of the deprecated INTL_IDNA_VARIANT_2003.

MySQLi

The embedded server functionality has been removed. It was broken since at least PHP 7.0.

The undocumented mysqli::$stat property has been removed in favor of mysqli::stat().

OpenSSL

The openssl_random_pseudo_bytes() function will now throw an exception in error situations, similar to random_bytes(). In particular, an Error is thrown if the number of requested bytes is less than or equal to zero, and an Exception is thrown if sufficient randomness cannot be gathered. The $crypto_strong output argument is guaranteed to always be true if the function does not throw, so explicitly checking it is not necessary.

Regular Expressions (Perl-Compatible)

When PREG_UNMATCHED_AS_NULL mode is used, trailing unmatched capturing groups will now also be set to null (or [null, -1] if offset capture is enabled). This means that the size of the $matches will always be the same.

PHP Data Objects

Attempting to serialize a PDO or PDOStatement instance will now generate an Exception rather than a PDOException, consistent with other internal classes which do not support serialization.

Reflection

Reflection objects will now generate an exception if an attempt is made to serialize them. Serialization for reflection objects was never supported and resulted in corrupted reflection objects. It has been explicitly prohibited now.

The values of the class constant of ReflectionClassConstant, ReflectionMethod and ReflectionProperty have changed.

Standard PHP Library (SPL)

Calling get_object_vars() on an ArrayObject instance will now always return the properties of the ArrayObject itself (or a subclass). Previously it returned the values of the wrapped array/object unless the ArrayObject::STD_PROP_LIST flag was specified.

Other affected operations are:

(array) casts are not affected. They will continue to return either the wrapped array, or the ArrayObject properties, depending on whether the ArrayObject::STD_PROP_LIST flag is used.

SplPriorityQueue::setExtractFlags() will throw an exception if zero is passed. Previously this would generate a recoverable fatal error on the next extraction operation.

ArrayObject, ArrayIterator, SplDoublyLinkedList and SplObjectStorage now support the __serialize() and __unserialize() mechanism in addition to the Serializable interface. This means that serialization payloads created on older PHP versions can still be unserialized, but new payloads created by PHP 7.4 will not be understood by older versions.

Tokenizer

token_get_all() will now emit a T_BAD_CHARACTER token for unexpected characters instead of leaving behind holes in the token stream.

Incoming Cookies

As of PHP 7.4.11, the names of incoming cookies are no longer url-decoded for security reasons.

PHP 7.3

Backward Incompatible Changes

PHP Core

Heredoc/Nowdoc Ending Label Interpretation

Due to the introduction of flexible heredoc/nowdoc syntax, doc strings that contain the ending label inside their body may cause syntax errors or change in interpretation. For example in:

<?php
$str 
= <<<FOO
abcdefg
   FOO
FOO;
?>
the indented occurrence of FOO did not previously have any special meaning. Now it will be interpreted as the end of the heredoc string and the following FOO; will cause a syntax error. This issue can always be resolved by choosing an ending label that does not occur within the contents of the string.

Continue Targeting Switch issues Warning

continue statements targeting switch control flow structures will now generate a warning. In PHP such continue statements are equivalent to break, while they behave as continue 2 in other languages.

<?php
while ($foo) {
    switch (
$bar) {
      case 
"baz":
         continue;
         
// Warning: "continue" targeting switch is equivalent to
         //          "break". Did you mean to use "continue 2"?
   
}
}
?>

Strict Interpretation of Integer String Keys on ArrayAccess

Array accesses of type $obj["123"], where $obj implements ArrayAccess and "123" is an integer string literal will no longer result in an implicit conversion to integer, i.e., $obj->offsetGet("123") will be called instead of $obj->offsetGet(123). This matches existing behavior for non-literals. The behavior of arrays is not affected in any way, they continue to implicitly convert integral string keys to integers.

Static Properties no longer separated by Reference Assignment

In PHP, static properties are shared between inheriting classes, unless the static property is explicitly overridden in a child class. However, due to an implementation artifact it was possible to separate the static properties by assigning a reference. This loophole has been fixed.

<?php
class Test {
    public static 
$x 0;
}
class 
Test2 extends Test { }

Test2::$x = &$x;
$x 1;

var_dump(Test::$xTest2::$x);
// Previously: int(0), int(1)
// Now:        int(1), int(1)
?>

References returned by Array and Property Accesses are immediately unwrapped

References returned by array and property accesses are now unwrapped as part of the access. This means that it is no longer possible to modify the reference between the access and the use of the accessed value:

<?php
$arr 
= [1];
$ref =& $arr[0];
var_dump($arr[0] + ($arr[0] = 2));
// Previously: int(4), Now: int(3)
?>
This makes the behavior of references and non-references consistent. Please note that reading and writing a value inside a single expression remains undefined behavior and may change again in the future.

Argument Unpacking of Traversables with non-Integer Keys no longer supported

Argument unpacking stopped working with Traversables with non-integer keys. The following code worked in PHP 5.6-7.2 by accident.

<?php
function foo(...$args) {
    
var_dump($args);
}
function 
gen() {
    yield 
1.23 => 123;
}
foo(...gen());
?>

Miscellaneous

The ext_skel utility has been completely redesigned with new options and some old options removed. This is now written in PHP and has no external dependencies.

Support for BeOS has been dropped.

Exceptions thrown due to automatic conversion of warnings into exceptions in EH_THROW mode (e.g. some DateTime exceptions) no longer populate error_get_last() state. As such, they now work the same way as manually thrown exceptions.

TypeError now reports wrong types as int and bool instead of integer and boolean, respectively.

Undefined variables passed to compact() will now be reported as a notice.

getimagesize() and related functions now report the mime type of BMP images as image/bmp instead of image/x-ms-bmp, since the former has been registered with the IANA (see » RFC 7903).

stream_socket_get_name() will now return IPv6 addresses wrapped in brackets. For example "[::1]:1337" will be returned instead of "::1:1337".

BCMath Arbitrary Precision Mathematics

All warnings thrown by BCMath functions are now using PHP's error handling. Formerly some warnings have directly been written to stderr.

bcmul() and bcpow() now return numbers with the requested scale. Formerly, the returned numbers may have omitted trailing decimal zeroes.

IMAP, POP3 and NNTP

rsh/ssh logins are disabled by default. Use imap.enable_insecure_rsh if you want to enable them. Note that the IMAP library does not filter mailbox names before passing them to the rsh/ssh command, thus passing untrusted data to this function with rsh/ssh enabled is insecure.

Multibyte String

Due to added support for named captures, mb_ereg_*() patterns using named captures will behave differently. In particular named captures will be part of matches and mb_ereg_replace() will interpret additional syntax. See Named Captures for more information.

MySQL Improved Extension

Prepared statements now properly report the fractional seconds for DATETIME, TIME and TIMESTAMP columns with decimals specifier (e.g. TIMESTAMP(6) when using microseconds). Formerly, the fractional seconds part was simply omitted from the returned values.

MySQL Functions (PDO_MYSQL)

Prepared statements now properly report the fractional seconds for DATETIME, TIME and TIMESTAMP columns with decimals specifier (e.g. TIMESTAMP(6) when using microseconds). Formerly, the fractional seconds part was simply omitted from the returned values. Please note that this only affects the usage of PDO_MYSQL with emulated prepares turned off (e.g. using the native preparation functionality). Statements using connections having PDO::ATTR_EMULATE_PREPARES=true (which is the default) were not affected by the bug fixed and have already been getting the proper fractional seconds values from the engine.

Reflection

Reflection export to string now uses int and bool instead of integer and boolean, respectively.

Standard PHP Library (SPL)

If an SPL autoloader throws an exception, following autoloaders will not be executed. Previously all autoloaders were executed and exceptions were chained.

SimpleXML

Mathematic operations involving SimpleXML objects will now treat the text as an int or float, whichever is more appropriate. Previously values were treated as ints unconditionally.

Incoming Cookies

As of PHP 7.3.23, the names of incoming cookies are no longer url-decoded for security reasons.

PHP 7.2

Backward incompatible changes

Prevent number_format() from returning negative zero

Previously, it was possible for the number_format() function to return -0. Whilst this is perfectly valid according to the IEEE 754 floating point specification, this oddity was not desirable for displaying formatted numbers in a human-readable form.

<?php

var_dump
(number_format(-0.01)); // now outputs string(1) "0" instead of string(2) "-0"

Convert numeric keys in object and array casts

Numeric keys are now better handled when casting arrays to objects and objects to arrays (either from explicit casting or by settype()).

This means that integer (or stringy integer) keys from arrays being casted to objects are now accessible:

<?php

// array to object
$arr = [=> 1];
$obj = (object)$arr;
var_dump(
    
$obj,
    
$obj->{'0'}, // now accessible
    
$obj->{0// now accessible
);

The above example will output:

object(stdClass)#1 (1) {
  ["0"]=>    // string key now, rather than integer key
  int(1)
}
int(1)
int(1)

And integer (or stringy integer) keys from objects being casted to arrays are now accessible:

<?php

// object to array
$obj = new class {
    public function 
__construct()
    {
        
$this->{0} = 1;
    }
};
$arr = (array)$obj;
var_dump(
    
$arr,
    
$arr[0], // now accessible
    
$arr['0'// now accessible
);

The above example will output:

array(1) {
  [0]=>    // integer key now, rather than string key
  int(1)
}
int(1)
int(1)

Disallow passing null to get_class()

Previously, passing null to the get_class() function would output the name of the enclosing class. This behaviour has now been removed, where an E_WARNING will be output instead. To achieve the same behaviour as before, the argument should simply be omitted.

Warn when counting non-countable types

An E_WARNING will now be emitted when attempting to count() non-countable types (this includes the sizeof() alias function).

<?php

var_dump
(
    
count(null), // NULL is not countable
    
count(1), // integers are not countable
    
count('abc'), // strings are not countable
    
count(new stdclass), // objects not implementing the Countable interface are not countable
    
count([1,2]) // arrays are countable
);

The above example will output:

Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d

Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d

Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d

Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d
int(0)
int(1)
int(1)
int(1)
int(2)

Move ext/hash from resources to objects

As part of the long-term migration away from resources, the Hash extension has been updated to use objects instead of resources. The change should be seamless for PHP developers, except for where is_resource() checks have been made (which will need updating to is_object() instead).

Improve SSL/TLS defaults

The following changes to the defaults have been made:

  • tls:// now defaults to TLSv1.0 or TLSv1.1 or TLSv1.2
  • ssl:// an alias of tls://
  • STREAM_CRYPTO_METHOD_TLS_* constants default to TLSv1.0 or TLSv1.1 + TLSv1.2, instead of TLSv1.0 only

gettype() return value on closed resources

Previously, using gettype() on a closed resource would return a string of "unknown type". Now, a string of "resource (closed)" will be returned.

is_object() and __PHP_Incomplete_Class

Previously, using is_object() on the __PHP_Incomplete_Class class would return false. Now, true will be returned.

Promote the error level of undefined constants

Unqualified references to undefined constants will now generate an E_WARNING (instead of an E_NOTICE). In the next major version of PHP, they will generate Error exceptions.

Windows support

The officially supported, minimum Windows versions are now Windows 7/Server 2008 R2.

Checks on default property values of traits

Compatibility checks upon default trait property values will no longer perform casting.

object for class names

The object name was previously soft-reserved in PHP 7.0. This is now hard-reserved, prohibiting it from being used as a class, trait, or interface name.

NetWare support

Support for NetWare has now been removed.

array_unique() with SORT_STRING

While array_unique() with SORT_STRING formerly copied the array and removed non-unique elements (without packing the array afterwards), now a new array is built by adding the unique elements. This can result in different numeric indexes.

bcmod() changes with floats

The bcmod() function no longer truncates fractional numbers to integers. As such, its behavior now follows fmod(), rather than the % operator. For example bcmod('4', '3.5') now returns 0.5 instead of 1.

Hashing functions and non-cryptographic hashes

The hash_hmac(), hash_hmac_file(), hash_pbkdf2(), and hash_init() (with HASH_HMAC) functions no longer accept non-cryptographic hashes.

json_decode() function options

The json_decode() function option, JSON_OBJECT_AS_ARRAY, is now used if the second parameter (assoc) is null. Previously, JSON_OBJECT_AS_ARRAY was always ignored.

rand() and mt_rand() output

Sequences generated by rand() and mt_rand() for a specific seed may differ from PHP 7.1 on 64-bit machines (due to the fixing of a modulo bias bug in the implementation).

Removal of sql.safe_mode ini setting

The sql.safe_mode ini setting has now been removed.

Changes to date_parse() and date_parse_from_format()

The zone element of the array returned by date_parse() and date_parse_from_format() represents seconds instead of minutes now, and its sign is inverted. For instance -120 is now 7200.

Incoming Cookies

As of PHP 7.2.34, the names of incoming cookies are no longer url-decoded for security reasons.

PHP 7.1

Backward incompatible changes

Throw on passing too few function arguments

Previously, a warning would be emitted for invoking user-defined functions with too few arguments. Now, this warning has been promoted to an Error exception. This change only applies to user-defined functions, not internal functions. For example:

<?php
function test($param){}
test();

The above example will output something similar to:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed in %s on line %d and exactly 1 expected in %s:%d

Forbid dynamic calls to scope introspection functions

Dynamic calls for certain functions have been forbidden (in the form of $func() or array_map('extract', ...), etc). These functions either inspect or modify another scope, and present with them ambiguous and unreliable behavior. The functions are as follows:

<?php
(function () {
    
$func 'func_num_args';
    
$func();
})();

The above example will output:

Warning: Cannot call func_num_args() dynamically in %s on line %d

Invalid class, interface, and trait names

The following names cannot be used to name classes, interfaces, or traits:

Numerical string conversions now respect scientific notation

Integer operations and conversions on numerical strings now respect scientific notation. This also includes the (int) cast operation, and the following functions: intval() (where the base is 10), settype(), decbin(), decoct(), and dechex().

Fixes to mt_rand() algorithm

mt_rand() will now default to using the fixed version of the Mersenne Twister algorithm. If deterministic output from mt_rand() was relied upon, then MT_RAND_PHP can be used as optional second parameter to mt_srand() to preserve the old (incorrect) implementation.

rand() aliased to mt_rand() and srand() aliased to mt_srand()

rand() and srand() have now been made aliases to mt_rand() and mt_srand(), respectively. This means that the output for the following functions have changed: rand(), shuffle(), str_shuffle(), and array_rand().

Disallow the ASCII delete control character in identifiers

The ASCII delete control character (0x7F) can no longer be used in identifiers that are not quoted.

error_log changes with syslog value

If the error_log ini setting is set to syslog, the PHP error levels are mapped to the syslog error levels. This brings finer differentiation in the error logs in contrary to the previous approach where all the errors are logged with the notice level only.

Do not call destructors on incomplete objects

Destructors are now never called for objects that throw an exception during the execution of their constructor. In previous versions this behavior depended on whether the object was referenced outside the constructor (e.g. by an exception backtrace).

call_user_func() handling of reference arguments

call_user_func() will now always generate a warning upon calls to functions that expect references as arguments. Previously this depended on whether the call was fully qualified.

Additionally, call_user_func() and call_user_func_array() will no longer abort the function call in this case. The "expected reference" warning will be emitted, but the call will proceed as usual.

The empty index operator is not supported for strings anymore

Applying the empty index operator to a string (e.g. $str[] = $x) throws a fatal error instead of converting silently to array.

Assignment via string index access on an empty string

String modification by character on an empty string now works like for non-empty strings, i.e. writing to an out of range offset pads the string with spaces, where non-integer types are converted to integer, and only the first character of the assigned string is used. Formerly, empty strings where silently treated like an empty array.

<?php
$a 
'';
$a[10] = 'foo';
var_dump($a);
?>

Output of the above example in PHP 7.0:

array(1) {
  [10]=>
  string(3) "foo"
}

Output of the above example in PHP 7.1:

string(11) "          f"

Removed ini directives

The following ini directives have been removed:

  • session.entropy_file
  • session.entropy_length
  • session.hash_function
  • session.hash_bits_per_character

Array ordering when elements are automatically created during by reference assignments has changed

The order of the elements in an array has changed when those elements have been automatically created by referencing them in a by reference assignment. For example:

<?php
$array 
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

Output of the above example in PHP 7.0:

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

Output of the above example in PHP 7.1:

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

Sort order of equal elements

The internal sorting algorithm has been improved, what may result in different sort order of elements, which compare as equal, than before.

Note:

Don't rely on the order of elements which compare as equal; it might change anytime.

Error message for E_RECOVERABLE errors

The error message for E_RECOVERABLE errors has been changed from "Catchable fatal error" to "Recoverable fatal error".

$options parameter of unserialize()

The allowed_classes element of the $options parameter of unserialize() is now strictly typed, i.e. if anything other than an array or a bool is given, unserialize() returns false and issues an E_WARNING.

DateTime constructor incorporates microseconds

DateTime and DateTimeImmutable now properly incorporate microseconds when constructed from the current time, either explicitly or with a relative string (e.g. "first day of next month"). This means that naive comparisons of two newly created instances will now more likely return false instead of true:

<?php
new DateTime() == new DateTime();
?>

Fatal errors to Error exceptions conversions

In the Date extension, invalid serialization data for DateTime or DatePeriod classes, or timezone initialization failure from serialized data, will now throw an Error exception from the __wakeup() or __set_state() methods, instead of resulting in a fatal error.

In the DBA extension, data modification functions (such as dba_insert()) will now throw an Error exception instead of triggering a catchable fatal error if the key does not contain exactly two elements.

In the DOM extension, invalid schema or RelaxNG validation contexts will now throw an Error exception instead of resulting in a fatal error. Similarly, attempting to register a node class that does not extend the appropriate base class, or attempting to read an invalid property or write to a readonly property, will also now throw an Error exception.

In the IMAP extension, email addresses longer than 16385 bytes will throw an Error exception instead of resulting in a fatal error.

In the Intl extension, failing to call the parent constructor in a class extending Collator before invoking the parent methods will now throw an Error instead of resulting in a recoverable fatal error. Also, cloning a Transliterator object will now throw an Error exception on failure to clone the internal transliterator instead of resulting in a fatal error.

In the LDAP extension, providing an unknown modification type to ldap_batch_modify() will now throw an Error exception instead of resulting in a fatal error.

In the mbstring extension, the mb_ereg() and mb_eregi() functions will now throw a ParseError exception if an invalid PHP expression is provided and the 'e' option is used.

In the Mcrypt extension, the mcrypt_encrypt() and mcrypt_decrypt() will now throw an Error exception instead of resulting in a fatal error if mcrypt cannot be initialized.

In the mysqli extension, attempting to read an invalid property or write to a readonly property will now throw an Error exception instead of resulting in a fatal error.

In the Reflection extension, failing to retrieve a reflection object or retrieve an object property will now throw an Error exception instead of resulting in a fatal error.

In the Session extension, custom session handlers that do not return strings for session IDs will now throw an Error exception instead of resulting in a fatal error when a function is called that must generate a session ID.

In the SimpleXML extension, creating an unnamed or duplicate attribute will now throw an Error exception instead of resulting in a fatal error.

In the SPL extension, attempting to clone an SplDirectory object will now throw an Error exception instead of resulting in a fatal error. Similarly, calling ArrayIterator::append() when iterating over an object will also now throw an Error exception.

In the standard extension, the assert() function, when provided with a string argument as its first parameter, will now throw a ParseError exception instead of resulting in a catchable fatal error if the PHP code is invalid. Similarly, calling forward_static_call() outside of a class scope will now throw an Error exception.

In the Tidy extension, creating a tidyNode manually will now throw an Error exception instead of resulting in a fatal error.

In the WDDX extension, a circular reference when serializing will now throw an Error exception instead of resulting in a fatal error.

In the XML-RPC extension, a circular reference when serializing will now throw an instance of Error exception instead of resulting in a fatal error.

In the Zip extension, the ZipArchive::addGlob() method will now throw an Error exception instead of resulting in a fatal error if glob support is not available.

Lexically bound variables cannot reuse names

Variables bound to a closure via the use construct cannot use the same name as any superglobals, $this, or any parameter. For example, all of these function definition will result in a fatal error:

<?php
$f 
= function () use ($_SERVER) {};
$f = function () use ($this) {};
$f = function ($param) use ($param) {};

long2ip() parameter type change

long2ip() now expects an int instead of a string.

JSON encoding and decoding

The serialize_precision ini setting now controls the serialization precision when encoding floats.

Decoding an empty key now results in an empty property name, rather than _empty_ as a property name.

<?php
var_dump
(json_decode(json_encode(['' => 1])));

The above example will output something similar to:

object(stdClass)#1 (1) {
  [""]=>
  int(1)
}

When supplying the JSON_UNESCAPED_UNICODE flag to json_encode(), the sequences U+2028 and U+2029 are now escaped.

Changes to mb_ereg() and mb_eregi() parameter semantics

The third parameter to the mb_ereg() and mb_eregi() functions (regs) will now be set to an empty array if nothing was matched. Formerly, the parameter would not have been modified.

Drop support for the sslv2 stream

The sslv2 stream has now been dropped in OpenSSL.

Forbid "return;" for typed returns already at compile-time

Return statements without argument in functions which declare a return type now trigger E_COMPILE_ERROR (unless the return type is declared as void), even if the return statement would never be reached.

PHP 7.0

Backward incompatible changes

Changes to error and exception handling

Many fatal and recoverable fatal errors have been converted to exceptions in PHP 7. These error exceptions inherit from the Error class, which itself implements the Throwable interface (the new base interface all exceptions inherit).

This means that custom error handlers may no longer be triggered because exceptions may be thrown instead (causing new fatal errors for uncaught Error exceptions).

A fuller description of how errors operate in PHP 7 can be found on the PHP 7 errors page. This migration guide will merely enumerate the changes that affect backward compatibility.

set_exception_handler() is no longer guaranteed to receive Exception objects

Code that implements an exception handler registered with set_exception_handler() using a type declaration of Exception will cause a fatal error when an Error object is thrown.

If the handler needs to work on both PHP 5 and 7, you should remove the type declaration from the handler, while code that is being migrated to work on PHP 7 exclusively can simply replace the Exception type declaration with Throwable instead.

<?php
// PHP 5 era code that will break.
function handler(Exception $e) { ... }
set_exception_handler('handler');

// PHP 5 and 7 compatible.
function handler($e) { ... }

// PHP 7 only.
function handler(Throwable $e) { ... }
?>

Internal constructors always throw exceptions on failure

Previously, some internal classes would return null or an unusable object when the constructor failed. All internal classes will now throw an Exception in this case in the same way that user classes already had to.

Parse errors throw ParseError

Parser errors now throw a ParseError object. Error handling for eval() should now include a catch block that can handle this error.

E_STRICT notices severity changes

All of the E_STRICT notices have been reclassified to other levels. E_STRICT constant is retained, so calls like error_reporting(E_ALL|E_STRICT) will not cause an error.

E_STRICT notices severity changes
Situation New level/behaviour
Indexing by a resource E_NOTICE
Abstract static methods Notice removed, triggers no error
"Redefining" a constructor Notice removed, triggers no error
Signature mismatch during inheritance E_WARNING
Same (compatible) property in two used traits Notice removed, triggers no error
Accessing static property non-statically E_NOTICE
Only variables should be assigned by reference E_NOTICE
Only variables should be passed by reference E_NOTICE
Calling non-static methods statically E_DEPRECATED

Changes to variable handling

PHP 7 now uses an abstract syntax tree when parsing source files. This has permitted many improvements to the language which were previously impossible due to limitations in the parser used in earlier versions of PHP, but has resulted in the removal of a few special cases for consistency reasons, which has resulted in backward compatibility breaks. These cases are detailed in this section.

Changes to the handling of indirect variables, properties, and methods

Indirect access to variables, properties, and methods will now be evaluated strictly in left-to-right order, as opposed to the previous mix of special cases. The table below shows how the order of evaluation has changed.

Old and new evaluation of indirect expressions
Expression PHP 5 interpretation PHP 7 interpretation
$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()
Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()

Code that used the old right-to-left evaluation order must be rewritten to explicitly use that evaluation order with curly braces (see the above middle column). This will make the code both forwards compatible with PHP 7.x and backwards compatible with PHP 5.x.

This also affects the global keyword. The curly brace syntax can be used to emulate the previous behaviour if required:

<?php
function f() {
    
// Valid in PHP 5 only.
    
global $$foo->bar;

    
// Valid in PHP 5 and 7.
    
global ${$foo->bar};
}
?>

Changes to list() handling

list() no longer assigns variables in reverse order

list() will now assign values to variables in the order they are defined, rather than reverse order. In general, this only affects the case where list() is being used in conjunction with the array [] operator, as shown below:

<?php
list($a[], $a[], $a[]) = [123];
var_dump($a);
?>

Output of the above example in PHP 5:

array(3) {
  [0]=>
  int(3)
  [1]=>
  int(2)
  [2]=>
  int(1)
}

Output of the above example in PHP 7:

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

In general, it is recommended not to rely on the order in which list() assignments occur, as this is an implementation detail that may change again in the future.

Empty list() assignments have been removed

list() constructs can no longer be empty. The following are no longer allowed:

<?php
list() = $a;
list(,,) = 
$a;
list(
$x, list(), $y) = $a;
?>
list() cannot unpack strings

list() can no longer unpack string variables. str_split() should be used instead.

Array ordering when elements are automatically created during by reference assignments has changed

The order of the elements in an array has changed when those elements have been automatically created by referencing them in a by reference assignment. For example:

<?php
$array 
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

Output of the above example in PHP 5:

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

Output of the above example in PHP 7:

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

Parentheses around function arguments no longer affect behaviour

In PHP 5, using redundant parentheses around a function argument could quiet strict standards warnings when the function argument was passed by reference. The warning will now always be issued.

<?php
function getArray() {
    return [
123];
}

function 
squareArray(array &$a) {
    foreach (
$a as &$v) {
        
$v **= 2;
    }
}

// Generates a warning in PHP 7.
squareArray((getArray()));
?>

The above example will output:

Notice: Only variables should be passed by reference in /tmp/test.php on line 13

Changes to foreach

Minor changes have been made to the behaviour of the foreach control structure, primarily around the handling of the internal array pointer and modification of the array being iterated over.

foreach no longer changes the internal array pointer

Prior to PHP 7, the internal array pointer was modified while an array was being iterated over with foreach. This is no longer the case, as shown in the following example:

<?php
$array 
= [012];
foreach (
$array as &$val) {
    
var_dump(current($array));
}
?>

Output of the above example in PHP 5:

int(1)
int(2)
bool(false)

Output of the above example in PHP 7:

int(0)
int(0)
int(0)

foreach by-value operates on a copy of the array

When used in the default by-value mode, foreach will now operate on a copy of the array being iterated rather than the array itself. This means that changes to the array made during iteration will not affect the values that are iterated.

foreach by-reference has improved iteration behaviour

When iterating by-reference, foreach will now do a better job of tracking changes to the array made during iteration. For example, appending to an array while iterating will now result in the appended values being iterated over as well:

<?php
$array 
= [0];
foreach (
$array as &$val) {
    
var_dump($val);
    
$array[1] = 1;
}
?>

Output of the above example in PHP 5:

int(0)

Output of the above example in PHP 7:

int(0)
int(1)

Iteration of non-Traversable objects

Iterating over a non-Traversable object will now have the same behaviour as iterating over by-reference arrays. This results in the improved behaviour when modifying an array during iteration also being applied when properties are added to or removed from the object.

Changes to int handling

Invalid octal literals

Previously, octal literals that contained invalid numbers were silently truncated (0128 was taken as 012). Now, an invalid octal literal will cause a parse error.

Negative bitshifts

Bitwise shifts by negative numbers will now throw an ArithmeticError:

<?php
var_dump
(>> -1);
?>

Output of the above example in PHP 5:

int(0)

Output of the above example in PHP 7:

Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2
Stack trace:
#0 {main}
  thrown in /tmp/test.php on line 2

Out of range bitshifts

Bitwise shifts (in either direction) beyond the bit width of an int will always result in 0. Previously, the behaviour of such shifts was architecture dependent.

Changes to Division By Zero

Previously, when 0 was used as the divisor for either the divide (/) or modulus (%) operators, an E_WARNING would be emitted and false would be returned. Now, the divide operator returns a float as either +INF, -INF, or NAN, as specified by IEEE 754. The modulus operator E_WARNING has been removed and will throw a DivisionByZeroError exception.

<?php
var_dump
(3/0);
var_dump(0/0);
var_dump(0%0);
?>

Output of the above example in PHP 5:

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

Output of the above example in PHP 7:

Warning: Division by zero in %s on line %d
float(INF)

Warning: Division by zero in %s on line %d
float(NAN)

PHP Fatal error:  Uncaught DivisionByZeroError: Modulo by zero in %s line %d

Changes to string handling

Hexadecimal strings are no longer considered numeric

Strings containing hexadecimal numbers are no longer considered to be numeric. For example:

<?php
var_dump
("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" "0x1");
var_dump(substr("foo""0x1"));
?>

Output of the above example in PHP 5:

bool(true)
bool(true)
int(15)
string(2) "oo"

Output of the above example in PHP 7:

bool(false)
bool(false)
int(0)

Notice: A non well formed numeric value encountered in /tmp/test.php on line 5
string(3) "foo"

filter_var() can be used to check if a string contains a hexadecimal number, and also to convert a string of that type to an int:

<?php
$str 
"0xffff";
$int filter_var($strFILTER_VALIDATE_INTFILTER_FLAG_ALLOW_HEX);
if (
false === $int) {
    throw new 
Exception("Invalid integer!");
}
var_dump($int); // int(65535)
?>

\u{ may cause errors

Due to the addition of the new Unicode codepoint escape syntax, strings containing a literal \u{ followed by an invalid sequence will cause a fatal error. To avoid this, the leading backslash should be escaped.

Removed functions

call_user_method() and call_user_method_array()

These functions were deprecated in PHP 4.1.0 in favour of call_user_func() and call_user_func_array(). You may also want to consider using variable functions and/or the ... operator.

All ereg* functions

All ereg functions were removed. PCRE is a recommended alternative.

mcrypt aliases

The deprecated mcrypt_generic_end() function has been removed in favour of mcrypt_generic_deinit().

Additionally, the deprecated mcrypt_ecb(), mcrypt_cbc(), mcrypt_cfb() and mcrypt_ofb() functions have been removed in favour of using mcrypt_decrypt() with the appropriate MCRYPT_MODE_* constant.

All ext/mysql functions

All ext/mysql functions were removed. For details about choosing a different MySQL API, see Choosing a MySQL API.

All ext/mssql functions

All ext/mssql functions were removed.

intl aliases

The deprecated datefmt_set_timezone_id() and IntlDateFormatter::setTimeZoneID() aliases have been removed in favour of datefmt_set_timezone() and IntlDateFormatter::setTimeZone(), respectively.

set_magic_quotes_runtime()

set_magic_quotes_runtime(), along with its alias magic_quotes_runtime(), have been removed. They were deprecated in PHP 5.3.0, and became effectively non-functional with the removal of magic quotes in PHP 5.4.0.

set_socket_blocking()

The deprecated set_socket_blocking() alias has been removed in favour of stream_set_blocking().

dl() in PHP-FPM

dl() can no longer be used in PHP-FPM. It remains functional in the CLI and embed SAPIs.

GD Type1 functions

Support for PostScript Type1 fonts has been removed from the GD extension, resulting in the removal of the following functions:

  • imagepsbbox()
  • imagepsencodefont()
  • imagepsextendfont()
  • imagepsfreefont()
  • imagepsloadfont()
  • imagepsslantfont()
  • imagepstext()

Using TrueType fonts and their associated functions is recommended instead.

Removed INI directives

Removed features

The following INI directives have been removed as their associated features have also been removed:

  • always_populate_raw_post_data
  • asp_tags

xsl.security_prefs

The xsl.security_prefs directive has been removed. Instead, the XsltProcessor::setSecurityPrefs() method should be called to control the security preferences on a per-processor basis.

Other backward incompatible changes

New objects cannot be assigned by reference

The result of the new statement can no longer be assigned to a variable by reference:

<?php
class {}
$c =& new C;
?>

Output of the above example in PHP 5:

Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3

Output of the above example in PHP 7:

Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3

Invalid class, interface and trait names

The following names cannot be used to name classes, interfaces or traits:

  • bool
  • int
  • float
  • string
  • null
  • true
  • false

Furthermore, the following names should not be used. Although they will not generate an error in PHP 7.0, they are reserved for future use and should be considered deprecated.

  • resource
  • object
  • mixed
  • numeric

ASP and script PHP tags removed

Support for using ASP and script tags to delimit PHP code has been removed. The affected tags are:

Removed ASP and script tags
Opening tag Closing tag
<% %>
<%= %>
<script language="php"> </script>

Calls from incompatible context removed

Previously deprecated in PHP 5.6, static calls made to a non-static method with an incompatible context will now result in the called method having an undefined $this variable and a deprecation warning being issued.

<?php
class {
    public function 
test() { var_dump($this); }
}

// Note: Does NOT extend A
class {
    public function 
callNonStaticMethodOfA() { A::test(); }
}

(new 
B)->callNonStaticMethodOfA();
?>

Output of the above example in PHP 5.6:

Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8
object(B)#1 (0) {
}

Output of the above example in PHP 7:

Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8

Notice: Undefined variable: this in /tmp/test.php on line 3
NULL

yield is now a right associative operator

The yield construct no longer requires parentheses, and has been changed to a right associative operator with precedence between print and =>. This can result in changed behaviour:

<?php
echo yield -1;
// Was previously interpreted as
echo (yield) - 1;
// And is now interpreted as
echo yield (-1);

yield 
$foo or die;
// Was previously interpreted as
yield ($foo or die);
// And is now interpreted as
(yield $foo) or die;
?>

Parentheses can be used to disambiguate those cases.

Functions cannot have multiple parameters with the same name

It is no longer possible to define two or more function parameters with the same name. For example, the following function will trigger an E_COMPILE_ERROR:

<?php
function foo($a$b$unused$unused) {
    
//
}
?>

Functions inspecting arguments report the current parameter value

func_get_arg(), func_get_args(), debug_backtrace() and exception backtraces will no longer report the original value that was passed to a parameter, but will instead provide the current value (which might have been modified).

<?php
function foo($x) {
    
$x++;
    
var_dump(func_get_arg(0));
}
foo(1);?>

Output of the above example in PHP 5:

1

Output of the above example in PHP 7:

2

Switch statements cannot have multiple default blocks

It is no longer possible to define two or more default blocks in a switch statement. For example, the following switch statement will trigger an E_COMPILE_ERROR:

<?php
switch (1) {
    default:
    break;
    default:
    break;
}
?>

$HTTP_RAW_POST_DATA removed

$HTTP_RAW_POST_DATA is no longer available. The php://input stream should be used instead.

# comments in INI files removed

Support for prefixing comments with # in INI files has been removed. ; (semi-colon) should be used instead. This change applies to php.ini, as well as files handled by parse_ini_file() and parse_ini_string().

JSON extension replaced with JSOND

The JSON extension has been replaced with JSOND, causing three minor BC breaks. Firstly, a number must not end in a decimal point (i.e. 34. must be changed to either 34.0 or 34). Secondly, when using scientific notation, the e exponent must not immediately follow a decimal point (i.e. 3.e3 must be changed to either 3.0e3 or 3e3). Finally, an empty string is no longer considered valid JSON.

Internal function failure on overflow

Previously, internal functions would silently truncate numbers produced from float-to-integer coercions when the float was too large to represent as an integer. Now, an E_WARNING will be emitted and null will be returned.

Fixes to custom session handler return values

Any predicate functions implemented by custom session handlers that return either false or -1 will be fatal errors. If any value from these functions other than a boolean, -1, or 0 is returned, then it will fail and an E_WARNING will be emitted.

Sort order of equal elements

The internal sorting algorithm has been improved, what may result in different sort order of elements, which compare as equal, than before.

Note:

Don't rely on the order of elements which compare as equal; it might change anytime.

Misplaced break and continue statements

break and continue statements outside of a loop or switch control structure are now detected at compile-time instead of run-time as before, and trigger an E_COMPILE_ERROR.

Mhash is not an extension anymore

The Mhash extension has been fully integrated into the Hash extension. Therefore, it is no longer possible to detect Mhash support with extension_loaded(); use function_exists() instead. Furthermore, Mhash is no longer reported by get_loaded_extensions() and related features.

declare(ticks)

The declare(ticks) directive does no longer leak into different compilation units.

PHP 5.6

Backward incompatible changes

Although most existing PHP 5 code should work without changes, please take note of some backward incompatible changes:

Array keys won't be overwritten when defining an array as a property of a class via an array literal

Previously, arrays declared as class properties which mixed explicit and implicit keys could have array elements silently overwritten if an explicit key was the same as a sequential implicit key. For example:

<?php
class {
    const 
ONE 1;
    public 
$array = [
        
self::ONE => 'foo',
        
'bar',
        
'quux',
    ];
}

var_dump((new C)->array);
?>

Output of the above example in PHP 5.5:

array(2) {
  [0]=>
  string(3) "bar"
  [1]=>
  string(4) "quux"
}

Output of the above example in PHP 5.6:

array(3) {
  [1]=>
  string(3) "foo"
  [2]=>
  string(3) "bar"
  [3]=>
  string(4) "quux"
}

json_decode() strictness

json_decode() now rejects non-lowercase variants of the JSON literals true, false and null at all times, as per the JSON specification, and sets json_last_error() accordingly. Previously, inputs to json_decode() that consisted solely of one of these values in upper or mixed case were accepted.

This change will only affect cases where invalid JSON was being passed to json_decode(): valid JSON input is unaffected and will continue to be parsed normally.

Stream wrappers now verify peer certificates and host names by default when using SSL/TLS

All encrypted client streams now enable peer verification by default. By default, this will use OpenSSL's default CA bundle to verify the peer certificate. In most cases, no changes will need to be made to communicate with servers with valid SSL certificates, as distributors generally configure OpenSSL to use known good CA bundles.

The default CA bundle may be overridden on a global basis by setting either the openssl.cafile or openssl.capath configuration setting, or on a per request basis by using the cafile or capath context options.

While not recommended in general, it is possible to disable peer certificate verification for a request by setting the verify_peer context option to false, and to disable peer name validation by setting the verify_peer_name context option to false.

GMP resources are now objects

GMP resources are now objects. The functional API implemented in the GMP extension has not changed, and code should run unmodified unless it checks explicitly for a resource using is_resource() or similar.

Mcrypt functions now require valid keys and IVs

mcrypt_encrypt(), mcrypt_decrypt(), mcrypt_cbc(), mcrypt_cfb(), mcrypt_ecb(), mcrypt_generic() and mcrypt_ofb() will no longer accept keys or IVs with incorrect sizes, and block cipher modes that require IVs will now fail if an IV isn't provided.

cURL file uploads

Uploads using the @file syntax now require CURLOPT_SAFE_UPLOAD to be set to false. CURLFile should be used instead.

PHP 5.5

Backward Incompatible Changes

Although most existing PHP 5 code should work without changes, please take note of some backward incompatible changes:

Windows XP and 2003 support dropped

Support for Windows XP and 2003 has been dropped. Windows builds of PHP now require Windows Vista or newer.

Case insensitivity no longer locale specific

All case insensitive matching for function, class and constant names is now performed in a locale independent manner according to ASCII rules. This improves support for languages using the Latin alphabet with unusual collating rules, such as Turkish and Azeri.

This may cause issues for code that uses case insensitive matches for non-ASCII characters in multibyte character sets (including UTF-8), such as accented characters in many European languages. If you have a non-English, non-ASCII code base, then you will need to test that you are not inadvertently relying on this behaviour before deploying PHP 5.5 to production systems.

pack() and unpack() changes

Changes were made to pack() and unpack() to make them more compatible with Perl:

  • pack() now supports the "Z" format code, which behaves identically to "a".
  • unpack() now support the "Z" format code for NULL padded strings, and behaves as "a" did in previous versions: it will strip trailing NULL bytes.
  • unpack() now keeps trailing NULL bytes when the "a" format code is used.
  • unpack() now strips all trailing ASCII whitespace when the "A" format code is used.

Writing backward compatible code that uses the "a" format code with unpack() requires the use of version_compare(), due to the backward compatibility break.

For example:

<?php
// Old code:
$data unpack('a5'$packed);

// New code:
if (version_compare(PHP_VERSION'5.5.0-dev''>=')) {
  
$data unpack('Z5'$packed);
} else {
  
$data unpack('a5'$packed);
}
?>

json_encode() changes

When the value passed to json_encode() triggers a JSON encoding error, FALSE is returned instead of partial output, unless options contains JSON_PARTIAL_OUTPUT_ON_ERROR. See json_last_error() for the full list of reasons that can cause JSON encoding to fail. One of the potential failure reasons is that value contains strings containing invalid UTF-8.

self, parent and static are now always case insensitive

Prior to PHP 5.5, cases existed where the self, parent, and static keywords were treated in a case sensitive fashion. These have now been resolved, and these keywords are always handled case insensitively: SELF::CONSTANT is now treated identically to self::CONSTANT.

PHP logo GUIDs removed

The GUIDs that previously resulted in PHP outputting various logos have been removed. This includes the removal of the functions to return those GUIDs. The removed functions are:

Internal execution changes

Extension authors should note that the zend_execute() function can no longer be overridden, and that numerous changes have been made to the execute_data struct and related function and method handling opcodes.

Most extension authors are unlikely to be affected, but those writing extensions that hook deeply into the Zend Engine should read the notes on these changes.

PHP 5.4

Backward Incompatible Changes

Although most existing PHP 5 code should work without changes, please take note of some backward incompatible changes:

  • Safe mode is no longer supported. Any applications that rely on safe mode may need adjustment, in terms of security.
  • Magic quotes has been removed. Applications relying on this feature may need to be updated, to avoid security issues. get_magic_quotes_gpc() and get_magic_quotes_runtime() now always return FALSE. set_magic_quotes_runtime() raises an E_CORE_ERROR level error on trying to enable Magic quotes.
  • The register_globals and register_long_arrays php.ini directives have been removed.
  • The mbstring.script_encoding directive has been removed. Use zend.script_encoding instead.
  • Call-time pass by reference has been removed.
  • The break and continue statements no longer accept variable arguments (e.g., break 1 + foo() * $bar;). Static arguments still work, such as break 2;. As a side effect of this change break 0; and continue 0; are no longer allowed.
  • The default character set for htmlspecialchars(), htmlentities() and html_entity_decode() is now UTF-8, instead of ISO-8859-1. Note that changing your output charset via the default_charset configuration setting does not affect htmlspecialchars/htmlentities unless you are passing "" (an empty string) as the encoding parameter to your htmlspecialchars()/htmlentities()/html_entity_decode() calls. Generally we do not recommend doing this because you should be able to change your output charset without affecting the runtime charset used by these functions. The safest approach is to explicitly set the charset on each call to htmlspecialchars(), htmlentities() and html_entity_decode().
  • In the date and time extension, the timezone can no longer be set using the TZ environment variable. Instead you have to specify a timezone using the date.timezone php.ini option or date_default_timezone_set() function. PHP will no longer attempt to guess the timezone, and will instead fall back to "UTC" and issue a E_WARNING.
  • Non-numeric string offsets - e.g. $a['foo'] where $a is a string - now return false on isset() and true on empty(), and produce a E_WARNING if you try to use them. Offsets of types double, bool and null produce a E_NOTICE. Numeric strings (e.g. $a['2']) still work as before. Note that offsets like '12.3' and '5 foobar' are considered non-numeric and produce a E_WARNING, but are converted to 12 and 5 respectively, for backward compatibility reasons. Note: Following code returns different result. $str='abc';var_dump(isset($str['x'])); // false for PHP 5.4 or later, but true for 5.3 or less
  • Converting an array to a string will now generate an E_NOTICE level error, but the result of the cast will still be the string "Array".
  • Turning NULL, FALSE, or an empty string into an object by adding a property will now emit an E_WARNING level error, instead of E_STRICT.
  • Parameter names that shadow super globals now cause a fatal error. This prohibits code like function foo($_GET, $_POST) {}.
  • The Salsa10 and Salsa20 hash algorithms have been removed.
  • The Tiger hash algorithm now uses big-endian byte ordering. Please follow this example to write code that is compatible with both PHP 5.3 and 5.4.
  • array_combine() now returns array() instead of FALSE when two empty arrays are provided as parameters.
  • If you use htmlentities() with asian character sets, it works like htmlspecialchars() - this has always been the case in previous versions of PHP, but now an E_STRICT level error is emitted.
  • The third parameter of ob_start() has changed from boolean erase to integer flags. Note that code that explicitly set erase to FALSE will no longer behave as expected in PHP 5.4: please follow this example to write code that is compatible with PHP 5.3 and 5.4.

The following keywords are now reserved, and may not be used as names by functions, classes, etc.

The following functions have been removed from PHP:

PHP 5.3

Backward Incompatible Changes

Although most existing PHP 5 code should work without changes, please take note of some backward incompatible changes:

  • The newer internal parameter parsing API has been applied across all the extensions bundled with PHP 5.3.x. This parameter parsing API causes functions to return NULL when passed incompatible parameters. There are some exceptions to this rule, such as the get_class() function, which will continue to return FALSE on error.
  • clearstatcache() no longer clears the realpath cache by default.
  • realpath() is now fully platform-independent. Consequence of this is that invalid relative paths such as __FILE__ . "/../x" do not work anymore.
  • The call_user_func() family of functions now propagate $this even if the callee is a parent class.
  • The array functions natsort(), natcasesort(), usort(), uasort(), uksort(), array_flip(), and array_unique() no longer accept objects passed as arguments. To apply these functions to an object, cast the object to an array first.
  • The behaviour of functions with by-reference parameters called by value has changed. Where previously the function would accept the by-value argument, a fatal error is now emitted. Any previous code passing constants or literals to functions expecting references, will need altering to assign the value to a variable before calling the function.
  • The new mysqlnd library necessitates the use of MySQL 4.1's newer 41-byte password format. Continued use of the old 16-byte passwords will cause mysql_connect() and similar functions to emit the error, "mysqlnd cannot connect to MySQL 4.1+ using old authentication."
  • The new mysqlnd library does not read mysql configuration files (my.cnf/my.ini), as the older libmysqlclient library does. If your code relies on settings in the configuration file, you can load it explicitly with the mysqli_options() function. Note that this means the PDO specific constants PDO::MYSQL_ATTR_READ_DEFAULT_FILE and PDO::MYSQL_ATTR_READ_DEFAULT_GROUP are not defined if MySQL support in PDO is compiled with mysqlnd.
  • The trailing / has been removed from the SplFileInfo class and other related directory classes.
  • The __toString() magic method can no longer accept arguments.
  • The magic methods __get(), __set(), __isset(), __unset(), and __call() must always be public and can no longer be static. Method signatures are now enforced.
  • The __call() magic method is now invoked on access to private and protected methods.
  • func_get_arg(), func_get_args() and func_num_args() can no longer be called from the outermost scope of a file that has been included by calling include or require from within a function in the calling file.
  • An emulation layer for the MHASH extension to wrap around the Hash extension have been added. However not all the algorithms are covered, notable the s2k hashing algorithm. This means that s2k hashing is no longer available as of PHP 5.3.0.

The following keywords are now reserved and may not be used in function, class, etc. names.

PHP 5.2

Backward Incompatible Changes

Although most existing PHP 5 code should work without changes, you should pay attention to the following backward incompatible changes:

  • getrusage() returns NULL when passed incompatible arguments as of PHP 5.2.1.
  • ZipArchive::setCommentName() returns TRUE on success as of PHP 5.2.1.
  • ZipArchive::setCommentIndex() returns TRUE on success as of PHP 5.2.1.
  • SplFileObject::getFilename() returns the filename, not relative/path/to/file, as of PHP 5.2.1.
  • Changed priority of PHPRC environment variable on Win32 The PHPRC environment variable now takes priority over the path stored in the Windows registry.
  • CLI SAPI no longer checks cwd for php.ini or the php-cli.ini file In PHP 5.1.x an undocumented feature was added that made the CLI binary check the current working directory for a PHP configuration file, potentially leading to unpredictable behavior if an unexpected configuration file were read. This functionality was removed in 5.2.0, and PHP will no longer search CWD for the presence of php.ini or php-cli.ini files. See also the command line section of the manual.
  • Added a warning when performing modulus 0 operations In earlier versions of PHP, performing integer % 0 did not emit any warning messages, instead returning an unexpected return value of FALSE. As of PHP 5.2.0, this operation will emit an E_WARNING, as is the case in all other instances where division by zero is performed.
    <?php
    print 10 0;
    /* Warning:  Division by zero in filename on line n */
    ?>
  • Changed __toString() to be called wherever applicable. The magic method __toString() will now be called in a string context, that is, anywhere an object is used as a string. The fallback of returning a string that contains the object identifier was dropped in PHP 5.2.0. It became problematic because an object identifier cannot be considered unique. This change will mean that your application is flawed if you have relied on the object identifier as a return value. An attempt to use that value as a string will now result in a catchable fatal error.
    <?php
    class foo {}
    $foo = new foo;
    print 
    $foo;
    /* Catchable fatal error:  Object of class foo could
       not be converted to string in filename on line n */
    ?>
    Even with __toString(), objects cannot be used as array indices or keys. We may add built-in hash support for this at a later date, but as of PHP 5.2.x you will need to either provide your own hashing or use the new SPL function spl_object_hash(). Exceptions can not be thrown from __toString() methods.
    <?php
    class foo {
        public function 
    __toString() {
            throw new 
    Exception;
        }
    }

    try {
        print new 
    foo;
        
    /* Fatal error:  Method foo::__toString() must
           not throw an exception in filename on line n */
    } catch(Exception $e) {}
    ?>
  • Dropped abstract static class functions. Due to an oversight, PHP 5.0.x and 5.1.x allowed abstract static functions in classes. As of PHP 5.2.x, only interfaces can have them.
    <?php
    abstract class foo {
        abstract static function 
    bar();
        
    /* Strict Standards:  Static function foo::bar()
           should not be abstract in filename on line n */
    }
    ?>
  • Oracle extension requires at least Oracle 10 on Windows.
  • Added RFC2397 (data: stream) support. The introduction of the 'data' URL scheme has the potential to lead to a change of behavior under Windows. If you are working with a NTFS file system and making use of meta streams in your application, and if you just happen to be using a file with the name 'data:' that is accessed without any path information - it won't work any more. The fix is to use the 'file:' protocol when accessing it. See also » RFC 2397
    <?php
    /* when allow_url_include is OFF (default) */
    include "data:;base64,PD9waHAgcGhwaW5mbygpOz8+";
    /* Warning:  include(): URL file-access is disabled
       in the server configuration in filename on line n */
    ?>
  • Regression in glob() patterns In version 5.2.4 a security fix caused a regression for patterns of the form "/foo/*/bar/*". Since version 5.2.5 instead of raising a warning the glob() function will return FALSE when openbase_dir restrictions are violated.

PHP 5.0

Backward Incompatible Changes

Although most existing PHP 4 code should work without changes, you should pay attention to the following backward incompatible changes:

  • There are some new reserved keywords.
  • strrpos() and strripos() now use the entire string as a needle.
  • Illegal use of string offsets causes E_ERROR instead of E_WARNING. An example illegal use is: $str = 'abc'; unset($str[0]);.
  • array_merge() was changed to accept only arrays. If a non-array variable is passed, a E_WARNING will be thrown for every such parameter. Be careful because your code may start emitting E_WARNING out of the blue.
  • PATH_TRANSLATED server variable is no longer set implicitly under Apache2 SAPI in contrast to the situation in PHP 4, where it is set to the same value as the SCRIPT_FILENAME server variable when it is not populated by Apache. This change was made to comply with the » CGI/1.1 specification. Please refer to » bug #23610 for further information, and see also the $_SERVER['PATH_TRANSLATED'] description in the manual. This issue also affects PHP versions >= 4.3.2.
  • The T_ML_COMMENT constant is no longer defined by the Tokenizer extension. If error_reporting is set to E_ALL, PHP will generate a notice. Although the T_ML_COMMENT was never used at all, it was defined in PHP 4. In both PHP 4 and PHP 5 // and /* */ are resolved as the T_COMMENT constant. However the PHPDoc style comments /** */, which starting PHP 5 are parsed by PHP, are recognized as T_DOC_COMMENT.
  • $_SERVER should be populated with argc and argv if variables_order includes "S". If you have specifically configured your system to not create $_SERVER, then of course it shouldn't be there. The change was to always make argc and argv available in the CLI version regardless of the variables_order setting. As in, the CLI version will now always populate the global $argc and $argv variables.
  • An object with no properties is no longer considered "empty".
  • In some cases classes must be declared before use. It only happens if some of the new features of PHP 5 (such as interfaces) are used. Otherwise the behaviour is the old.
  • get_class(), get_parent_class() and get_class_methods() now return the name of the classes/methods as they were declared (case-sensitive) which may lead to problems in older scripts that rely on the previous behaviour (the class/method name was always returned lowercased). A possible solution is to search for those functions in all your scripts and use strtolower(). This case sensitivity change also applies to the magical predefined constants __CLASS__, __METHOD__, and __FUNCTION__. The values are returned exactly as they're declared (case-sensitive).
  • ip2long() now returns FALSE when an invalid IP address is passed as argument to the function, and no longer -1.
  • If there are functions defined in the included file, they can be used in the main file independent if they are before return or after. If the file is included twice, PHP 5 issues fatal error because functions were already declared, while PHP 4 doesn't complain about it. It is recommended to use include_once instead of checking if the file was already included and conditionally return inside the included file.
  • include_once and require_once first normalize the path of included file on Windows so that including A.php and a.php include the file just once.
  • Passing an array to a function by value no longer resets the array's internal pointer for array accesses made within the function. In other words, in PHP 4 when you passed an array to a function, its internal pointer inside the function would be reset, while in PHP 5, when you pass an array to a function, its array pointer within the function will be wherever it was when the array was passed to the function.

Example #1 strrpos() and strripos() now use the entire string as a needle

<?php
var_dump
(strrpos('ABCDEF','DEF')); //int(3)

var_dump(strrpos('ABCDEF','DAF')); //bool(false)
?>

Example #2 An object with no properties is no longer considered "empty"

<?php
class test { }
$t = new test();

var_dump(empty($t)); // echo bool(false)

if ($t) {
    
// Will be executed
}
?>

Example #3 In some cases classes must be declared before used

<?php

//works with no errors:
$a = new a();
class 
{
}


//throws an error:
$a = new b();

interface 
c{
}
class 
implements {


?>

PHP 8.1

PHP 7.3

PHP 7.2

New functions

Sodium

PHP 7.0

PHP 5.6

PHP 5.5

New Functions

Intl

  • datefmt_format_object()
  • datefmt_get_calendar_object()
  • datefmt_get_timezone()
  • datefmt_set_timezone()
  • datefmt_get_calendar_object()
  • intlcal_create_instance()
  • intlcal_get_keyword_values_for_locale()
  • intlcal_get_now()
  • intlcal_get_available_locales()
  • intlcal_get()
  • intlcal_get_time()
  • intlcal_set_time()
  • intlcal_add()
  • intlcal_set_time_zone()
  • intlcal_after()
  • intlcal_before()
  • intlcal_set()
  • intlcal_roll()
  • intlcal_clear()
  • intlcal_field_difference()
  • intlcal_get_actual_maximum()
  • intlcal_get_actual_minimum()
  • intlcal_get_day_of_week_type()
  • intlcal_get_first_day_of_week()
  • intlcal_get_greatest_minimum()
  • intlcal_get_least_maximum()
  • intlcal_get_locale()
  • intlcal_get_maximum()
  • intlcal_get_minimal_days_in_first_week()
  • intlcal_get_minimum()
  • intlcal_get_time_zone()
  • intlcal_get_type()
  • intlcal_get_weekend_transition()
  • intlcal_in_daylight_time()
  • intlcal_is_equivalent_to()
  • intlcal_is_lenient()
  • intlcal_is_set()
  • intlcal_is_weekend()
  • intlcal_set_first_day_of_week()
  • intlcal_set_lenient()
  • intlcal_equals()
  • intlcal_get_repeated_wall_time_option()
  • intlcal_get_skipped_wall_time_option()
  • intlcal_set_repeated_wall_time_option()
  • intlcal_set_skipped_wall_time_option()
  • intlcal_from_date_time()
  • intlcal_to_date_time()
  • intlcal_get_error_code()
  • intlcal_get_error_message()
  • intlgregcal_create_instance()
  • intlgregcal_set_gregorian_change()
  • intlgregcal_get_gregorian_change()
  • intlgregcal_is_leap_year()
  • intltz_create_time_zone()
  • intltz_create_default()
  • intltz_get_id()
  • intltz_get_gmt()
  • intltz_get_unknown()
  • intltz_create_enumeration()
  • intltz_count_equivalent_ids()
  • intltz_create_time_zone_id_enumeration()
  • intltz_get_canonical_id()
  • intltz_get_region()
  • intltz_get_tz_data_version()
  • intltz_get_equivalent_id()
  • intltz_use_daylight_time()
  • intltz_get_offset()
  • intltz_get_raw_offset()
  • intltz_has_same_rules()
  • intltz_get_display_name()
  • intltz_get_dst_savings()
  • intltz_from_date_time_zone()
  • intltz_to_date_time_zone()
  • intltz_get_error_code()
  • intltz_get_error_message()

PHP 5.4

PHP 5.3

New Functions

PHP 5.3 introduced some new functions:

PHP Core:

Date/Time:

GMP:

Hash:

IMAP:

JSON:

MySQL Improved:

OpenSSL:

PCNTL:

PCRE:

  • preg_filter() - Perform a regular expression search and replace, returning only results which matched the pattern.

Semaphore:

The following functions are now natively implemented, making them available on all operating systems which can run PHP:

PHP 5.2

New Functions

PHP 5.2.x introduced some new functions:

PHP Core:

Image:

libXML:

mbstring:

  • mb_stripos() - Finds position of first occurrence of a string within another, case insensitive
  • mb_stristr() - Finds first occurrence of a string within another, case insensitive
  • mb_strrchr() - Finds the last occurrence of a character in a string within another
  • mb_strrichr() - Finds the last occurrence of a character in a string within another, case insensitive
  • mb_strripos() - Finds position of last occurrence of a string within another, case insensitive
  • mb_strstr() - Finds first occurrence of a string within another

ming (As of PHP 5.2.1):

  • void ming_setSWFCompression(int num) - Sets output compression
  • void swfmovie::namedanchor(string name) - Creates anchor
  • void swfmovie::protect([string password]) - Protects

openssl:

spl:

  • spl_object_hash() - Return hash id for given object
  • int iterator_apply(Traversable it, mixed function [, mixed params]) - Calls a function for every element in an iterator

pcre:

pgsql:

  • pg_field_table() - Returns the name of the table field belongs to, or table's oid if oid_only is TRUE

posix:

gmp:

xmlwriter:

PHP 5.0

New Functions

In PHP 5 there are some new functions. Here is the list of them:

Arrays:

  • array_combine() - Creates an array by using one array for keys and another for its values
  • array_diff_uassoc() - Computes the difference of arrays with additional index check which is performed by a user supplied callback function
  • array_udiff() - Computes the difference of arrays by using a callback function for data comparison
  • array_udiff_assoc() - Computes the difference of arrays with additional index check. The data is compared by using a callback function
  • array_udiff_uassoc() - Computes the difference of arrays with additional index check. The data is compared by using a callback function. The index check is done by a callback function also
  • array_walk_recursive() - Apply a user function recursively to every member of an array
  • array_uintersect_assoc() - Computes the intersection of arrays with additional index check. The data is compared by using a callback function
  • array_uintersect_uassoc() - Computes the intersection of arrays with additional index check. Both the data and the indexes are compared by using separate callback functions
  • array_uintersect() - Computes the intersection of arrays. The data is compared by using a callback function

InterBase:

iconv:

Streams:

Date and time related:

Strings:

  • str_split() - Convert a string to an array
  • strpbrk() - Search a string for any of a set of characters
  • substr_compare() - Binary safe optionally case insensitive comparison of two strings from an offset, up to length characters

Other:

Note:

The Tidy extension has also changed its API completely.

PHP 8.2

Deprecated Features

PHP Core

Usage of dynamic properties

The creation of dynamic properties is deprecated, unless the class opts in by using the #[\AllowDynamicProperties] attribute. stdClass allows dynamic properties. Usage of the __get()/__set() magic methods is not affected by this change. A dynamic properties deprecation warning can be addressed by:

  • Declaring the property (preferred).
  • Adding the #[\AllowDynamicProperties] attribute to the class (which also applies to all child classes).
  • Using a WeakMap if additional data needs to be associated with an object which one does not own.

Relative callables

Callables that are not accepted by the $callable() syntax (but are accepted by call_user_func()) are deprecated. In particular:

  • "self::method"
  • "parent::method"
  • "static::method"
  • ["self", "method"]
  • ["parent", "method"]
  • ["static", "method"]
  • ["Foo", "Bar::method"]
  • [new Foo, "Bar::method"]
This does not affect normal method callables such as "A::method" or ["A", "method"].

"${var}" and "${expr}" style interpolation

The "${var}" and "${expr}" style of string interpolation is deprecated. Use "$var"/"{$var}" and "{${expr}}", respectively.

MBString

Usage of the QPrint, Base64, Uuencode, and HTML-ENTITIES 'text encodings' is deprecated for all MBString functions. Unlike all the other text encodings supported by MBString, these do not encode a sequence of Unicode codepoints, but rather a sequence of raw bytes. It is not clear what the correct return values for most MBString functions should be when one of these non-encodings is specified. Moreover, PHP has separate, built-in implementations of all of them; for example, UUencoded data can be handled using convert_uuencode()/convert_uudecode().

SPL

The internal SplFileInfo::_bad_state_ex() method has been deprecated.

Standard

utf8_encode() and utf8_decode() have been deprecated.

PHP 8.1

Deprecated Features

PHP Core

Implementing Serializable without __serialize() and __unserialize()

Either only the new methods should be implemented, if no support for PHP prior to version 7.4 is provided, or both should be implemented.

Passing null to non-nullable parameters of built-in functions

Scalar types for built-in functions are nullable by default, this behaviour is deprecated to align with the behaviour of user-defined functions, where scalar types need to be marked as nullable explicitly.

<?php
var_dump
(str_contains("foobar"null));
// Deprecated: Passing null to parameter #2 ($needle) of type string
//             is deprecated
?>

Implicit incompatible float to int conversions

The implicit conversion of float to int which leads to a loss in precision is now deprecated. This affects array keys, int type declarations in coercive mode, and operators working on ints.

<?php
$a 
= [];
$a[15.5]; // deprecated, as key value loses the 0.5 component
$a[15.0]; // ok, as 15.0 == 15
?>

Calling a static element on a trait

Calling a static method, or accessing a static property directly on a trait is deprecated. Static methods and properties should only be accessed on a class using the trait.

Returning a non-array from __sleep()

Returning a value which is not an array from __sleep() now generates a diagnostic.

Returning by reference from a void function

<?php
function &test(): void {}
?>
Such a function is contradictory, and already emits the following E_NOTICE when called: Only variable references should be returned by reference.

Autovivification from false

Autovivification is the process of creating a new array when appending to a value. Autovivification is prohibited from scalar values, false however was an exception. This is now deprecated.

<?php
$arr 
false;
$arr[] = 2;   // deprecated
?>

Note:

Autovivification from null and undefined values is still allowed:

<?php
// From undefined
$arr[] = 'some value';
$arr['doesNotExist'][] = 2;
// From null
$arr null;
$arr[] = 2;
?>

ctype

Verifying non-string arguments

Passing a non-string argument is deprecated. In the future, the argument will be interpreted as a string instead of an ASCII codepoint. Depending on the intended behavior, the argument should either be cast to string or an explicit call to chr() should be made. All ctype_*() functions are affected.

Date

date_sunrise() and date_sunset() have been deprecated in favor of date_sun_info().

strptime() has been deprecated. Use date_parse_from_format() instead (for locale-independent parsing), or IntlDateFormatter::parse() (for locale-dependent parsing).

strftime() and gmstrftime() have been deprecated. Use date() instead (for locale-independent formatting), or IntlDateFormatter::format() (for locale-dependent formatting).

Filter

The FILTER_SANITIZE_STRING and FILTER_SANITIZE_STRIPPED filters are deprecated.

The filter.default INI directive is deprecated.

GD

The num_points of imagepolygon(), imageopenpolygon() and imagefilledpolygon() has been deprecated.

Hash

The mhash(), mhash_keygen_s2k(), mhash_count(), mhash_get_block_size(), and mhash_get_hash_name() have been deprecated. Use the hash_*() functions instead.

IMAP

The NIL constant has been deprecated. Use 0 instead.

Intl

Calling IntlCalendar::roll() with a bool argument is deprecated. Use 1 and -1 instead of true and false respectively.

Multibyte String

Calling mb_check_encoding() without any arguments is deprecated.

MySQLi

The mysqli_driver::$driver_version property has been deprecated. It was meaningless and outdated, use PHP_VERSION_ID instead.

Calling mysqli::get_client_info() or mysqli_get_client_info() with the mysqli argument has been deprecated. Call mysqli_get_client_info() without any arguments to obtain the version information of the client library.

The mysqli::init() method has been deprecated. Replace calls to parent::init() with parent::__construct().

OCI8

The oci8.old_oci_close_semantics INI directive is deprecated.

ODBC

odbc_result_all() has been deprecated.

PDO

The PDO::FETCH_SERIALIZE fetch mode has been deprecated.

PgSQL

Not passing the connection argument to all pgsql_*() functions has been deprecated.

SOAP

The ssl_method option of SoapClient::__construct() has been deprecated in favor of SSL stream context options.

Standard

Calling key(), current(), next(), prev(), reset(), or end() on objects is deprecated. Either use get_mangled_object_vars() on the object first, or use ArrayIterator.

The auto_detect_line_endings INI directive is deprecated. If necessary, handle "\r" line breaks manually instead.

The FILE_BINARY and FILE_TEXT constants have been deprecated. They never had any effect.

PHP 8.0

Deprecated Features

PHP Core

  • If a parameter with a default value is followed by a required parameter, the default value has no effect. This is deprecated as of PHP 8.0.0 and can generally be resolved by dropping the default value, without a change in functionality:

    <?php
    function test($a = [], $b) {} // Before
    function test($a$b) {}      // After
    ?>

    One exception to this rule are parameters of the form Type $param = null, where the null default makes the type implicitly nullable. This usage remains allowed, but it is recommended to use an explicit nullable type instead:

    <?php
    function test(A $a null$b) {} // Still allowed
    function test(?A $a$b) {}       // Recommended
    ?>
  • Calling get_defined_functions() with exclude_disabled explicitly set to false is deprecated and no longer has an effect. get_defined_functions() will never include disabled functions.

Enchant

LibXML

libxml_disable_entity_loader() has been deprecated. As libxml 2.9.0 is now required, external entity loading is guaranteed to be disabled by default, and this function is no longer needed to protect against XXE attacks, unless the (still vulnerable) LIBXML_NOENT is used. In that case, it is recommended to refactor the code using libxml_set_external_entity_loader() to suppress loading of external entities.

PGSQL / PDO PGSQL

Standard Library

  • Sort comparison functions that return true or false will now throw a deprecation warning, and should be replaced with an implementation that returns an integer less than, equal to, or greater than zero.

    <?php
    // Replace
    usort($arrayfn($a$b) => $a $b);
    // With
    usort($arrayfn($a$b) => $a <=> $b);
    ?>

Zip

  • Using an empty file as ZipArchive is deprecated. Libzip 1.6.0 does not accept empty files as valid zip archives any longer. The existing workaround will be removed in the next version.

  • The procedural API of Zip is deprecated. Use ZipArchive instead. Iteration over all entries can be accomplished using ZipArchive::statIndex() and a for loop:

    <?php
    // iterate using the procedural API
    assert(is_resource($zip));
    while (
    $entry zip_read($zip)) {
        echo 
    zip_entry_name($entry);
    }

    // iterate using the object-oriented API
    assert($zip instanceof ZipArchive);
    for (
    $i 0$entry $zip->statIndex($i); $i++) {
        echo 
    $entry['name'];
    }
    ?>

Reflection

PHP 7.4

Deprecated Features

PHP Core

Nested ternary operators without explicit parentheses

Nested ternary operations must explicitly use parentheses to dictate the order of the operations. Previously, when used without parentheses, the left-associativity would not result in the expected behaviour in most cases.

<?php
5;   // deprecated
(3) ? 5// ok
: (5); // ok
?>

Parentheses are not required when nesting into the middle operand, as this is always unambiguous and not affected by associativity:

1 ? 2 ? 3 : 4 : 5 // ok

Array and string offset access using curly braces

The array and string offset access syntax using curly braces is deprecated. Use $var[$idx] instead of $var{$idx}.

(real) cast and is_real() function

The (real) cast is deprecated, use (float) instead.

The is_real() function is also deprecated, use is_float() instead.

Unbinding $this when $this is used

Unbinding $this of a non-static closure that uses $this is deprecated.

parent keyword without parent class

Using parent inside a class without a parent is deprecated, and will throw a compile-time error in the future. Currently an error will only be generated if/when the parent is accessed at run-time.

allow_url_include INI option

The allow_url_include ini directive is deprecated. Enabling it will generate a deprecation notice at startup.

Invalid characters in base conversion functions

Passing invalid characters to base_convert(), bindec(), octdec() and hexdec() will now generate a deprecation notice. The result will still be computed as if the invalid characters did not exist. Leading and trailing whitespace, as well as prefixes of type 0x (depending on base) continue to be allowed.

Using array_key_exists() on objects

Using array_key_exists() on objects is deprecated. Instead either isset() or property_exists() should be used.

Magic quotes functions

The get_magic_quotes_gpc() and get_magic_quotes_runtime() functions are deprecated. They always return false.

hebrevc() function

The hebrevc() function is deprecated. It can be replaced with nl2br(hebrev($str)) or, preferably, the use of Unicode RTL support.

convert_cyr_string() function

The convert_cyr_string() function is deprecated. It can be replaced by one of mb_convert_string(), iconv() or UConverter.

money_format() function

The money_format() function is deprecated. It can be replaced by the intl NumberFormatter functionality.

ezmlm_hash() function

The ezmlm_hash() function is deprecated.

restore_include_path() function

The restore_include_path() function is deprecated. It can be replaced by ini_restore('include_path').

Implode with historical parameter order

Passing parameters to implode() in reverse order is deprecated, use implode($glue, $parts) instead of implode($parts, $glue).

COM

Importing type libraries with case-insensitive constant registering has been deprecated.

Filter

FILTER_SANITIZE_MAGIC_QUOTES is deprecated, use FILTER_SANITIZE_ADD_SLASHES instead.

Multibyte String

Passing a non-string pattern to mb_ereg_replace() is deprecated. Currently, non-string patterns are interpreted as ASCII codepoints. In PHP 8, the pattern will be interpreted as a string instead.

Passing the encoding as 3rd parameter to mb_strrpos() is deprecated. Instead pass a 0 offset, and encoding as 4th parameter.

Lightweight Directory Access Protocol

ldap_control_paged_result_response() and ldap_control_paged_result() are deprecated. Pagination controls can be sent along with ldap_search() instead.

Reflection

Calls to ReflectionType::__toString() now generate a deprecation notice. This method has been deprecated in favor of ReflectionNamedType::getName() in the documentation since PHP 7.1, but did not throw a deprecation notice for technical reasons.

The export() methods on all Reflection classes are deprecated. Construct a Reflection object and convert it to string instead:

<?php
// ReflectionClass::export(Foo::class, false) is:
echo new ReflectionClass(Foo::class), "\n";

// $str = ReflectionClass::export(Foo::class, true) is:
$str = (string) new ReflectionClass(Foo::class);
?>

Socket

The AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES flags for socket_addrinfo_lookup() are deprecated, due to an upstream deprecation in glibc.

PHP 7.3

Deprecated Features

PHP Core

Case-Insensitive Constants

The declaration of case-insensitive constants has been deprecated. Passing true as the third argument to define() will now generate a deprecation warning. The use of case-insensitive constants with a case that differs from the declaration is also deprecated.

Namespaced assert()

Declaring a function called assert() inside a namespace is deprecated. The assert() function is subject to special handling by the engine, which may lead to inconsistent behavior when defining a namespaced function with the same name.

Strip-Tags Streaming

The fgetss() function and the string.strip_tags stream filter have been deprecated. This also affects the SplFileObject::fgetss() method and gzgetss() function.

Data Filtering

The explicit usage of the constants FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED is now deprecated; both are implied for FILTER_VALIDATE_URL anyway.

Image Processing and GD

image2wbmp() has been deprecated.

Internationalization Functions

Usage of the Normalizer::NONE form throws a deprecation warning, if PHP is linked with ICU ≥ 56.

Multibyte String

The following undocumented mbereg_*() aliases have been deprecated. Use the corresponding mb_ereg_*() variants instead.

  • mbregex_encoding()
  • mbereg()
  • mberegi()
  • mbereg_replace()
  • mberegi_replace()
  • mbsplit()
  • mbereg_match()
  • mbereg_search()
  • mbereg_search_pos()
  • mbereg_search_regs()
  • mbereg_search_init()
  • mbereg_search_getregs()
  • mbereg_search_getpos()
  • mbereg_search_setpos()

ODBC and DB2 Functions (PDO_ODBC)

The pdo_odbc.db2_instance_name ini setting has been formally deprecated. It is deprecated in the documentation as of PHP 5.1.1.

PHP 7.2

Deprecated features in PHP 7.2.x

Unquoted strings

Unquoted strings that are non-existent global constants are taken to be strings of themselves. This behaviour used to emit an E_NOTICE, but will now emit an E_WARNING. In the next major version of PHP, an Error exception will be thrown instead.

<?php

var_dump
(NONEXISTENT);

/* Output:
Warning: Use of undefined constant NONEXISTENT - assumed 'NONEXISTENT' (this will throw an Error in a future version of PHP) in %s on line %d
string(11) "NONEXISTENT"
*/

png2wbmp() and jpeg2wbmp()

The png2wbmp() and jpeg2wbmp() functions from the GD extension have now been deprecated and will be removed in the next major version of PHP.

INTL_IDNA_VARIANT_2003 variant

The Intl extension has deprecated the INTL_IDNA_VARIANT_2003 variant, which is currently being used as the default for idn_to_ascii() and idn_to_utf8(). PHP 7.4 will see these defaults changed to INTL_IDNA_VARIANT_UTS46, and the next major version of PHP will remove INTL_IDNA_VARIANT_2003 altogether.

__autoload() method

The __autoload() method has been deprecated because it is inferior to spl_autoload_register() (due to it not being able to chain autoloaders), and there is no interoperability between the two autoloading styles.

track_errors ini setting and $php_errormsg variable

When the track_errors ini setting is enabled, a $php_errormsg variable is created in the local scope when a non-fatal error occurs. Given that the preferred way of retrieving such error information is by using error_get_last(), this feature has been deprecated.

create_function() function

Given the security issues of this function (being a thin wrapper around eval()), this dated function has now been deprecated. The preferred alternative is to use anonymous functions.

mbstring.func_overload ini setting

Given the interoperability problems of string-based functions being used in environments with this setting enabled, it has now been deprecated.

(unset) cast

Casting any expression to this type will always result in null, and so this superfluous casting type has now been deprecated.

parse_str() without a second argument

Without the second argument to parse_str(), the query string parameters would populate the local symbol table. Given the security implications of this, using parse_str() without a second argument has now been deprecated. The function should always be used with two arguments, as the second argument causes the query string to be parsed into an array.

gmp_random() function

This function generates a random number based upon a range that is calculated by an unexposed, platform-specific limb size. Because of this, the function has now been deprecated. The preferred way of generating a random number using the GMP extension is by gmp_random_bits() and gmp_random_range().

each() function

This function is far slower at iteration than a normal foreach, and causes implementation issues for some language changes. It has therefore been deprecated.

assert() with a string argument

Using assert() with a string argument required the string to be eval()'ed. Given the potential for remote code execution, using assert() with a string argument has now been deprecated in favour of using boolean expressions.

$errcontext argument of error handlers

The $errcontext argument contains all local variables of the error site. Given its rare usage, and the problems it causes with internal optimisations, it has now been deprecated. Instead, a debugger should be used to retrieve information on local variables at the error site.

read_exif_data() function

The read_exif_data() alias has been deprecated. The exif_read_data() function should be used instead.

PHP 7.1

Deprecated features in PHP 7.1.x

ext/mcrypt

The mcrypt extension has been abandonware for nearly a decade now, and was also fairly complex to use. It has therefore been deprecated in favour of OpenSSL, where it will be removed from the core and into PECL in PHP 7.2.

Eval option for mb_ereg_replace() and mb_eregi_replace()

The e pattern modifier has been deprecated for the mb_ereg_replace() and mb_eregi_replace() functions.

PHP 7.0

Deprecated features in PHP 7.0.x

PHP 4 style constructors

PHP 4 style constructors (methods that have the same name as the class they are defined in) are deprecated, and will be removed in the future. PHP 7 will emit E_DEPRECATED if a PHP 4 constructor is the only constructor defined within a class. Classes that implement a __construct() method are unaffected.

<?php
class foo {
    function 
foo() {
        echo 
'I am the constructor';
    }
}
?>

The above example will output:

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; foo has a deprecated constructor in example.php on line 3

Static calls to non-static methods

Static calls to methods that are not declared static are deprecated, and may be removed in the future.

<?php
class foo {
    function 
bar() {
        echo 
'I am not static!';
    }
}

foo::bar();
?>

The above example will output:

Deprecated: Non-static method foo::bar() should not be called statically in - on line 8
I am not static!

password_hash() salt option

The salt option for the password_hash() function has been deprecated to prevent developers from generating their own (usually insecure) salts. The function itself generates a cryptographically secure salt when no salt is provided by the developer - therefore custom salt generation should not be needed.

capture_session_meta SSL context option

The capture_session_meta SSL context option has been deprecated. SSL metadata is now available through the stream_get_meta_data() function.

LDAP deprecations

The following function has been deprecated:

PHP 5.6

Deprecated features in PHP 5.6.x

Calls from incompatible context

Methods called from an incompatible context are now deprecated, and will generate E_DEPRECATED errors when invoked instead of E_STRICT. Support for these calls will be removed in a future version of PHP.

An example of such a call is:

<?php
class {
    function 
f() { echo get_class($this); }
}

class 
{
    function 
f() { A::f(); }
}

(new 
B)->f();
?>

The above example will output:

Deprecated: Non-static method A::f() should not be called statically, assuming $this from incompatible context in - on line 7
B

$HTTP_RAW_POST_DATA and always_populate_raw_post_data

always_populate_raw_post_data will now generate an E_DEPRECATED error when $HTTP_RAW_POST_DATA is populated. New code should use php://input instead of $HTTP_RAW_POST_DATA, which will be removed in a future release. You can opt in for the new behaviour (in which $HTTP_RAW_POST_DATA is never defined hence no E_DEPRECATED error will be generated) by setting always_populate_raw_post_data to -1.

iconv and mbstring encoding settings

The iconv and mbstring configuration options related to encoding have been deprecated in favour of default_charset. The deprecated options are:

PHP 5.5

Deprecated features in PHP 5.5.x

ext/mysql deprecation

The original MySQL extension is now deprecated, and will generate E_DEPRECATED errors when connecting to a database. Instead, use the MySQLi or PDO_MySQL extensions.

preg_replace() /e modifier

The preg_replace() /e modifier is now deprecated. Instead, use the preg_replace_callback() function.

intl deprecations

IntlDateFormatter::setTimeZoneID() and datefmt_set_timezone_id() are now deprecated. Instead, use the IntlDateFormatter::setTimeZone() method and datefmt_set_timezone() function, respectively.

mcrypt deprecations

The following functions have been deprecated:

PHP 5.3

Deprecated features in PHP 5.3.x

PHP 5.3.0 introduces two new error levels: E_DEPRECATED and E_USER_DEPRECATED. The E_DEPRECATED error level is used to indicate that a function or feature has been deprecated. The E_USER_DEPRECATED level is intended for indicating deprecated features in user code, similarly to the E_USER_ERROR and E_USER_WARNING levels.

The following is a list of deprecated INI directives. Use of any of these INI directives will cause an E_DEPRECATED error to be thrown at startup.

Deprecated functions:

Deprecated features:

  • Assigning the return value of new by reference is now deprecated.
  • Call-time pass-by-reference is now deprecated.

PHP 8.2

New Features

PHP Core

SensitiveParameter Attribute

Added the #[\SensitiveParameter] attribute to redact sensitive data in backtraces.

error_log_mode INI directive

The error_log_mode INI directive has been added which allows setting the permissions for the error log file.

Enumerations properties in constant expressions

It is now possible to fetch properties of Enumerations in constant expressions.

Type System Improvements

It is now possible to use null and false as stand-alone types.

The true type has been added.

It is now possible to combine intersection and union types. The type needs to be written in DNF.

Constants in Traits

It is now possible to define constants in traits.

Readonly Classes

Support for readonly on classes has been added.

cURL

Added the CURLINFO_EFFECTIVE_METHOD option, which returns the effective HTTP method in the return value of curl_getinfo().

Exposed multiple new constants from libcurl 7.62 to 7.80.

Added the curl_upkeep() function to perform any connection upkeep checks.

DBA

The LMDB Driver now accepts the DBA_LMDB_USE_SUB_DIR or DBA_LMDB_NO_SUB_DIR flags to determine if it should create a subdirectory or not when creating a database file.

OCI8

Added the oci8.prefetch_lob_size INI directive and oci_set_prefetch_lob() function to tune LOB query performance by reducing the number of round-trips between PHP and Oracle Databases when fetching LOBS. This is usable with Oracle Database 12.2 or later.

OpenSSL

Added AEAD support for the chacha20-poly1305 algorithm.

ODBC

Added the odbc_connection_string_is_quoted(), odbc_connection_string_should_quote(), and odbc_connection_string_quote() functions. These are primarily used behind the scenes in the ODBC and PDO_ODBC extensions, but are exposed to userland for easier unit testing, and for user applications and libraries to perform quoting themselves.

PCRE

Added support for the n (NO_AUTO_CAPTURE) modifier, which makes simple (xyz) groups non-capturing. Only named groups like (?<name>xyz) are capturing. This only affects which groups are capturing, it is still possible to use numbered subpattern references, and the matches array will still contain numbered results.

Random

This is a new extension which organises and consolidates existing implementations related to random number generators. New and better RNGs are available with scope issues eliminated.

PHP 8.1

New Features

PHP Core

Integer Octal Literal Prefix

Octal integers can now use an explicit 0o/0O prefix in integer literals, similarly to binary and hexadecimal integer literals.

<?php
014
;  // Non-prefix octal literal
0o14// Prefixed octal literal
?>

Array Unpacking with String Keys

Added support for array unpacking with strings keys.

<?php
$arr1 
= [1'a' => 'b'];
$arr2 = [...$arr1'c' => 'd']; //[1, 'a' => 'b', 'c' => 'd']
?>

Named Argument After Argument Unpacking

It is now possible to specify named arguments after an argument unpack. e.g. foo(...$args, named: $arg).

full-path Key for File Uploads

File uploads now provide an additional full_path key, which contains the full path (rather than just the basename) of the uploaded file. This is intended for use in conjunction with "upload webkitdirectory".

Enumerations

Support for Enumerations has been added.

Fibers

Support for Fibers has been added.

First Class Callable Syntax

Closures for callables can now be created using the syntax myFunc(...), which is identical to Closure::fromCallable('myFunc').

Note: The ... is part of the syntax, and not an omission.

Intersection Types

Support for intersection types has been added.

Caution

Intersection types cannot be used together with union types

Never type

A new return only type never has been added. This indicates that a function either exit(), throws an exception, or doesn't terminate.

new in Initializers

It is now possible to use new ClassName() expressions as the default value of a parameter, static variable, global constant initializers, and as attribute arguments. Objects can also be passed to define() now.

Readonly properties

Support for readonly has been added.

Final class constants

Added support for the final modifier for class constants. Also, interface constants become overridable by default.

CURL

Added the CURLOPT_DOH_URL option.

Added options for blob certificate when libcurl >= 7.71.0:

  • CURLOPT_ISSUERCERT_BLOB
  • CURLOPT_PROXY_ISSUERCERT
  • CURLOPT_PROXY_ISSUERCERT_BLOB
  • CURLOPT_PROXY_SSLCERT_BLOB
  • CURLOPT_PROXY_SSLKEY_BLOB
  • CURLOPT_SSLCERT_BLOB
  • CURLOPT_SSLKEY_BLOB

Added CURLStringFile, which can be used to post a file from a string rather than a file:

<?php
$file 
= new CURLStringFile($data'filename.txt''text/plain');
curl_setopt($curlCURLOPT_POSTFIELDS, ['file' => $file]);
?>

FPM

Added openmetrics status format. It can be used by Prometheus to fetch FPM metrics.

Added new pool option for the dynamic process manager called pm.max_spawn_rate. It allows to start a number of children at a faster rate when dynamic pm is selected. The default value is 32 which was the previous hard coded value.

GD

Avif support is now available through imagecreatefromavif() and imageavif(), if libgd has been built with Avif support.

Hash

The following functions hash(), hash_file(), and hash_init() now support an additional optional options argument, which can be used to pass algorithm specific data.

MurmurHash3

Added support for MurmurHash3 with streaming support. The following variants are implemented:

  • murmur3a, 32-bit hash
  • murmur3c, 128-bit hash for x86
  • murmur3f, 128-bit hash for x64

The initial hash state can be passed through the seed key in the options array, for example:

<?php
$h 
hash("murmur3f"$dataoptions: ["seed" => 42]);
echo 
$h"\n";
?>
A valid seed value is within the range from 0 to the platform defined UINT_MAX, usually 4294967295.

xxHash

Added support for xxHash. The following variants are implemented:

  • xxh32, 32-bit hash
  • xxh64, 64-bit hash
  • xxh3, 64-bit hash
  • xxh128, 128-bit hash

The initial hash state can be passed through the seed key in the options array, for example:

<?php
$h 
hash("xxh3"$dataoptions: ["seed" => 42]);
echo 
$h"\n";
?>
Secret usage is supported through passing the secret key in the options array, too:
<?php
$h 
hash("xxh3"$dataoptions: ["secret" => "at least 136 bytes long secret here"]);
echo 
$h"\n";
?>
The quality of the custom secret is crucial for the quality of the resulting hash. It is highly recommended for the secret to use the best possible entropy.

MySQLi

New INI directive mysqli.local_infile_directory

The mysqli.local_infile_directory INI directive has been added, which can be used to specify a directory from which files are allowed to be loaded. It is only meaningful if mysqli.allow_local_infile is not enabled, as all directories are allowed in that case.

Binding parameters in execute

It is now possible to bind parameters by passing them as an array to mysqli_stmt::execute(). All values will be bound as strings. Only list arrays are allowed. This new feature is not available when MySQLi is compiled with libmysqlclient.

<?php
$stmt 
$mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)');
$stmt->execute([1$username]);
?>

New method mysqli_result::fetch_column()

mysqli_result::fetch_column() has been added to allow fetching a single scalar value from the result set. The new method accepts an optional 0-based column parameter of type int specifying which column to fetch from.

<?php
$result 
$mysqli->query('SELECT username FROM users WHERE id = 123');
echo 
$result->fetch_column();
?>

PDO

The PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY attribute has been added, which can be used to specify a directory from which files are allowed to be loaded. It is only meaningful if PDO::MYSQL_ATTR_LOCAL_INFILE is not enabled, as all directories are allowed in that case.

PDO_SQLite

SQLite's "file:" DSN syntax is now supported, which allows specifying additional flags. This feature is not available if open_basedir is set.

<?php
new PDO('sqlite:file:path/to/sqlite.db?mode=ro')
?>

POSIX

Added POSIX_RLIMIT_KQUEUES and POSIX_RLIMIT_NPTS. These rlimits are only available on FreeBSD.

Standard

fputcsv() now accepts a new eol argument which allows to define a custom End of Line sequence, the default remains the same and is "\n".

SPL

SplFileObject::fputcsv() now accepts a new eol argument which allows to define a custom End of Line sequence, the default remains the same and is "\n".

PHP 8.0

New Features

PHP Core

Named Arguments

Support for Named Arguments has been added.

Attributes

Support for Attributes has been added.

Constructor Property Promotion

Support for constructor property promotion (declaring properties in the constructor signature) has been added.

Union Types

Support for union types has been added.

Match Expression

Support for match expressions has been added.

Nullsafe Operator

Support for the nullsafe operator (?->) has been added.

Other new Features

  • The WeakMap class has been added.

  • The ValueError class has been added.

  • Any number of function parameters may now be replaced by a variadic argument, as long as the types are compatible. For example, the following code is now allowed:

    <?php
    class {
         public function 
    method(int $manystring $parameters$here) {}
    }
    class 
    extends {
         public function 
    method(...$everything) {}
    }
    ?>
  • static (as in "late static binding") can now be used as a return type:

    <?php
    class Test {
         public function 
    create(): static {
              return new static();
         }
    }
    ?>
  • It is now possible to fetch the class name of an object using $object::class. The result is the same as get_class($object).

  • new and instanceof can now be used with arbitrary expressions, using new (expression)(...$args) and $obj instanceof (expression).

  • Some consistency fixes to variable syntax have been applied, for example writing Foo::BAR::$baz is now allowed.

  • Added Stringable interface, which is automatically implemented if a class defines a __toString() method.

  • Traits can now define abstract private methods. Such methods must be implemented by the class using the trait.

  • throw can now be used as an expression. That allows usages like:

    <?php
    $fn 
    fn() => throw new Exception('Exception in arrow function');
    $user $session->user ?? throw new Exception('Must have user');
  • An optional trailing comma is now allowed in parameter lists.

    <?php
    function functionWithLongSignature(
        
    Type1 $parameter1,
        
    Type2 $parameter2// <-- This comma is now allowed.
    ) {
    }
  • It is now possible to write catch (Exception) to catch an exception without storing it in a variable.

  • Support for mixed type has been added.

  • Private methods declared on a parent class no longer enforce any inheritance rules on the methods of a child class (with the exception of final private constructors). The following example illustrates which restrictions have been removed:

    <?php
    class ParentClass {
        private function 
    method1() {}
        private function 
    method2() {}
        private static function 
    method3() {}
        
    // Throws a warning, as "final" no longer has an effect:
        
    private final function method4() {}
    }
    class 
    ChildClass extends ParentClass {
        
    // All of the following are now allowed, even though the modifiers aren't
        // the same as for the private methods in the parent class.
        
    public abstract function method1() {}
        public static function 
    method2() {}
        public function 
    method3() {}
        public function 
    method4() {}
    }
    ?>
  • get_resource_id() has been added, which returns the same value as (int) $resource. It provides the same functionality under a clearer API.

  • The InternalIterator has been added.

Date and Time

DOM

DOMParentNode and DOMChildNode with new traversal and manipulation APIs have been added.

Filter

FILTER_VALIDATE_BOOL has been added as an alias for FILTER_VALIDATE_BOOLEAN. The new name is preferred, as it uses the canonical type name.

Enchant

enchant_dict_add(), enchant_dict_is_added(), and LIBENCHANT_VERSION have been added.

FPM

Added a new option pm.status_listen that allows getting the status from different endpoint (e.g. port or UDS file) which is useful for getting the status when all children are busy with serving long running requests.

Hash

HashContext objects can now be serialized.

Internationalization Functions

The IntlDateFormatter::RELATIVE_FULL, IntlDateFormatter::RELATIVE_LONG, IntlDateFormatter::RELATIVE_MEDIUM, and IntlDateFormatter::RELATIVE_SHORT constants have been added.

LDAP

ldap_count_references() has been added, which returns the number of reference messages in a search result.

OPcache

If the opcache.record_warnings ini setting is enabled, OPcache will record compile-time warnings and replay them on the next include, even if it is served from cache.

OpenSSL

Added Cryptographic Message Syntax (CMS) (» RFC 5652) support composed of functions for encryption, decryption, signing, verifying and reading. The API is similar to the API for PKCS #7 functions with an addition of new encoding constants: OPENSSL_ENCODING_DER, OPENSSL_ENCODING_SMIME and OPENSSL_ENCODING_PEM:

  • openssl_cms_encrypt() encrypts the message in the file with the certificates and outputs the result to the supplied file.
  • openssl_cms_decrypt() that decrypts the S/MIME message in the file and outputs the results to the supplied file.
  • openssl_cms_read() that exports the CMS file to an array of PEM certificates.
  • openssl_cms_sign() that signs the MIME message in the file with a cert and key and output the result to the supplied file.
  • openssl_cms_verify() that verifies that the data block is intact, the signer is who they say they are, and returns the certs of the signers.

Regular Expressions (Perl-Compatible)

preg_last_error_msg() has been added, which returns a human-readable message for the last PCRE error. It complements preg_last_error(), which returns an integer enum value instead.

Reflection

SQLite3

SQLite3::setAuthorizer() and respective class constants have been added to set a userland callback that will be used to authorize or not an action on the database.

Standard Library

  • str_contains(), str_starts_with() and str_ends_with() have been added, which check whether haystack contains, starts with or ends with needle, respectively.

  • fdiv() has been added, which performs a floating-point division under IEEE 754 semantics. Division by zero is considered well-defined and will return one of Inf, -Inf or NaN.

  • get_debug_type() has been added, which returns a type useful for error messages. Unlike gettype(), it uses canonical type names, returns class names for objects, and indicates the resource type for resources.

  • printf() and friends now support the %h and %H format specifiers. These are the same as %g and %G, but always use "." as the decimal separator, rather than determining it through the LC_NUMERIC locale.

  • printf() and friends now support using "*" as width or precision, in which case the width/precision is passed as an argument to printf. This also allows using precision -1 with %g, %G, %h and %H. For example, the following code can be used to reproduce PHP's default floating point formatting:

    <?php
    printf
    ("%.*H", (int) ini_get("precision"), $float);
    printf("%.*H", (int) ini_get("serialize_precision"), $float);
    ?>
  • proc_open() now supports pseudo-terminal (PTY) descriptors. The following attaches stdin, stdout and stderr to the same PTY:

    <?php
    $proc 
    proc_open($command, [['pty'], ['pty'], ['pty']], $pipes);
    ?>
  • proc_open() now supports socket pair descriptors. The following attaches a distinct socket pair to stdin, stdout and stderr:

    <?php
    $proc 
    proc_open($command, [['socket'], ['socket'], ['socket']], $pipes);
    ?>

    Unlike pipes, sockets do not suffer from blocking I/O issues on Windows. However, not all programs may work correctly with stdio sockets.

  • Sorting functions are now stable, which means that equal-comparing elements will retain their original order.

  • array_diff(), array_intersect() and their variations can now be used with a single array as argument. This means that usages like the following are now possible:

    <?php
    // OK even if $excludes is empty:
    array_diff($array, ...$excludes);
    // OK even if $arrays only contains a single array:
    array_intersect(...$arrays);
    ?>
  • The flag parameter of ob_implicit_flush() was changed to accept a bool rather than an int.

Tokenizer

PhpToken adds an object-based interface to the tokenizer. It provides a more uniform and ergonomic representation, while being more memory efficient and faster.

Zip

PHP 7.4

New Features

PHP Core

Typed properties

Class properties now support type declarations.

<?php
class User {
    public 
int $id;
    public 
string $name;
}
?>
The above example will enforce that $user->id can only be assigned int values and $user->name can only be assigned string values.

Arrow functions

Arrow functions provide a shorthand syntax for defining functions with implicit by-value scope binding.

<?php
$factor 
10;
$nums array_map(fn($n) => $n $factor, [1234]);
// $nums = array(10, 20, 30, 40);
?>

Limited return type covariance and argument type contravariance

The following code will now work:

<?php
class {}
class 
extends {}

class 
Producer {
    public function 
method(): {}
}
class 
ChildProducer extends Producer {
    public function 
method(): {}
}
?>
Full variance support is only available if autoloading is used. Inside a single file only non-cyclic type references are possible, because all classes need to be available before they are referenced.

Null coalescing assignment operator

<?php
$array
['key'] ??= computeDefault();
// is roughly equivalent to
if (!isset($array['key'])) {
    
$array['key'] = computeDefault();
}
?>

Unpacking inside arrays

<?php
$parts 
= ['apple''pear'];
$fruits = ['banana''orange', ...$parts'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];
?>

Numeric literal separator

Numeric literals can contain underscores between digits.

<?php
6.674_083e
-11// float
299_792_458;   // decimal
0xCAFE_F00D;   // hexadecimal
0b0101_1111;   // binary
?>

Weak references

Weak references allow the programmer to retain a reference to an object that does not prevent the object from being destroyed.

Allow exceptions from __toString()

Throwing exceptions from __toString() is now permitted. Previously this resulted in a fatal error. Existing recoverable fatal errors in string conversions have been converted to Error exceptions.

CURL

CURLFile now supports stream wrappers in addition to plain file names, if the extension has been built against libcurl >= 7.56.0.

Filter

The FILTER_VALIDATE_FLOAT filter now supports the min_range and max_range options, with the same semantics as FILTER_VALIDATE_INT.

FFI

FFI is a new extension, which provides a simple way to call native functions, access native variables, and create/access data structures defined in C libraries.

GD

Added the IMG_FILTER_SCATTER image filter to apply a scatter filter to images.

Hash

Added crc32c hash using Castagnoli's polynomial. This CRC32 variant is used by storage systems, such as iSCSI, SCTP, Btrfs and ext4.

Multibyte String

Added the mb_str_split() function, which provides the same functionality as str_split(), but operating on code points rather than bytes.

OPcache

Support for preloading code has been added.

Regular Expressions (Perl-Compatible)

The preg_replace_callback() and preg_replace_callback_array() functions now accept an additional flags argument, with support for the PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags. This influences the format of the matches array passed to the callback function.

PDO

The username and password can now be specified as part of the PDO DSN for the mysql, mssql, sybase, dblib, firebird and oci drivers. Previously this was only supported by the pgsql driver. If a username/password is specified both in the constructor and the DSN, the constructor takes precedence.

It is now possible to escape question marks in SQL queries to avoid them being interpreted as parameter placeholders. Writing ?? allows sending a single question mark to the database and e.g. use the PostgreSQL JSON key exists (?) operator.

PDO_OCI

PDOStatement::getColumnMeta() is now available.

PDO_SQLite

PDOStatement::getAttribute(PDO::SQLITE_ATTR_READONLY_STATEMENT) allows checking whether the statement is read-only, i.e. if it doesn't modify the database.

PDO::setAttribute(PDO::SQLITE_ATTR_EXTENDED_RESULT_CODES, true) enables the use of SQLite3 extended result codes in PDO::errorInfo() and PDOStatement::errorInfo().

SQLite3

Added SQLite3::lastExtendedErrorCode() to fetch the last extended result code.

Added SQLite3::enableExtendedResultCodes($enable = true), which will make SQLite3::lastErrorCode() return extended result codes.

Standard

strip_tags() with array of tag names

strip_tags() now also accepts an array of allowed tags: instead of strip_tags($str, '<a><p>') you can now write strip_tags($str, ['a', 'p']).

Custom object serialization

A new mechanism for custom object serialization has been added, which uses two new magic methods: __serialize and __unserialize.

<?php
// Returns array containing all the necessary state of the object.
public function __serialize(): array;

// Restores the object state from the given data array.
public function __unserialize(array $data): void;
?>
The new serialization mechanism supersedes the Serializable interface, which will be deprecated in the future.

Array merge functions without arguments

array_merge() and array_merge_recursive() may now be called without any arguments, in which case they will return an empty array. This is useful in conjunction with the spread operator, e.g. array_merge(...$arrays).

proc_open() function

proc_open() now accepts an array instead of a string for the command. In this case the process will be opened directly (without going through a shell) and PHP will take care of any necessary argument escaping.

<?php
proc_open
(['php''-r''echo "Hello World\n";'], $descriptors$pipes);
?>

proc_open() now supports redirect and null descriptors.

<?php
// Like 2>&1 on the shell
proc_open($cmd, [=> ['pipe''w'], => ['redirect'1]], $pipes);
// Like 2>/dev/null or 2>nul on the shell
proc_open($cmd, [=> ['pipe''w'], => ['null']], $pipes);
?>

argon2i(d) without libargon

password_hash() now has the argon2i and argon2id implementations from the sodium extension when PHP is built without libargon.

PHP 7.3

New Features

PHP Core

More Flexible Heredoc and Nowdoc Syntax

The closing marker for doc strings is no longer required to be followed by a semicolon or newline. Additionally the closing marker may be indented, in which case the indentation will be stripped from all lines in the doc string.

Array Destructuring supports Reference Assignments

Array destructuring now supports reference assignments using the syntax [&$a, [$b, &$c]] = $d. The same is also supported for list().

Instanceof Operator accepts Literals

instanceof now allows literals as the first operand, in which case the result is always false.

CompileError Exception instead of some Compilation Errors

A new CompileError exception has been added, from which ParseError inherits. A small number of compilation errors will now throw a CompileError instead of generating a fatal error. Currently this only affects compilation errors that may be thrown by token_get_all() in TOKEN_PARSE mode, but more errors may be converted in the future.

Trailing Commas are allowed in Calls

Trailing commas in function and method calls are now allowed.

Argon2id Support

The --with-password-argon2[=dir] configure argument now provides support for both Argon2i and Argon2id hashes in the password_hash(), password_verify(), password_get_info(), and password_needs_rehash() functions. Passwords may be hashed and verified using the PASSWORD_ARGON2ID constant. Support for both Argon2i and Argon2id in the password_*() functions now requires PHP be linked against libargon2 reference library ≥ 20161029.

FastCGI Process Manager

New options have been added to customize the FPM logging:

log_limit
This global option can be used for setting the log limit for the logged line which allows to log messages longer than 1024 characters without wrapping. It also fixes various wrapping issues.
log_buffering
This global option allows an experimental logging without extra buffering.
decorate_workers_output
This pool option allows to disable the output decoration for workers output when catch_workers_output is enabled.

BC Math Functions

bcscale() can now also be used as getter to retrieve the current scale in use.

Lightweight Directory Access Protocol

Full support for LDAP Controls has been added to the LDAP querying functions and ldap_parse_result():

Multibyte String Functions

Full Case-Mapping and Case-Folding Support

Support for full case-mapping and case-folding has been added. Unlike simple case-mapping, full case-mapping may change the length of the string. For example:

<?php
mb_strtoupper
("Straße");
// Produces STRAßE on PHP 7.2
// Produces STRASSE on PHP 7.3
?>
The different casing mapping and folding modes are available through mb_convert_case():
  • MB_CASE_LOWER (used by mb_strtolower())
  • MB_CASE_UPPER (used by mb_strtoupper())
  • MB_CASE_TITLE
  • MB_CASE_FOLD
  • MB_CASE_LOWER_SIMPLE
  • MB_CASE_UPPER_SIMPLE
  • MB_CASE_TITLE_SIMPLE
  • MB_CASE_FOLD_SIMPLE (used by case-insensitive operations)
Only unconditional, language agnostic full case-mapping is performed.

Case-Insensitive String Operations use Case-Folding

Case-insensitive string operations now use case-folding instead of case- mapping during comparisons. This means that more characters will be considered (case insensitively) equal now.

MB_CASE_TITLE performs Title-Case Conversion

mb_convert_case() with MB_CASE_TITLE now performs title-case conversion based on the Cased and CaseIgnorable derived Unicode properties. In particular this also improves handling of quotes and apostrophes.

Unicode 11 Support

The Multibyte String data tables have been updated for Unicode 11.

Long String Support

The Multibyte String Functions now correctly support strings larger than 2GB.

Performance Improvements

Performance of the Multibyte String extension has been significantly improved across the board. The largest improvements are in case conversion functions.

Named Captures Support

The mb_ereg_* functions now support named captures. Matching functions like mb_ereg() will now return named captures both using their group number and their name, similar to PCRE:

<?php
mb_ereg
('(?<word>\w+)''国'$matches);
// => [0 => "国", 1 => "国", "word" => "国"];
?>
Additionally, mb_ereg_replace() now supports the \k<> and \k'' notations to reference named captures in the replacement string:
<?php
mb_ereg_replace
('\s*(?<word>\w+)\s*'"_\k<word>_\k'word'_"' foo ');
// => "_foo_foo_"
?>
\k<> and \k'' can also be used for numbered references, which also works with group numbers greater than 9.

Readline

Support for the completion_append_character and completion_suppress_append options has been added to readline_info(). These options are only available if PHP is linked against libreadline (rather than libedit).

PHP 7.2

New features

New object type

A new type, object, has been introduced that can be used for (contravariant) parameter typing and (covariant) return typing of any objects.

<?php

function test(object $obj) : object
{
    return new 
SplQueue();
}

test(new StdClass());

Extension loading by name

Shared extensions no longer require their file extension (.so for Unix or .dll for Windows) to be specified. This is enabled in the php.ini file, as well as in the dl() function.

Abstract method overriding

Abstract methods can now be overridden when an abstract class extends another abstract class.

<?php

abstract class A
{
    abstract function 
test(string $s);
}
abstract class 
extends A
{
    
// overridden - still maintaining contravariance for parameters and covariance for return
    
abstract function test($s) : int;
}

Sodium is now a core extension

The modern Sodium cryptography library has now become a core extension in PHP.

For a complete function reference, see the Sodium chapter.

Password hashing with Argon2

Argon2 has been added to the password hashing API, where the following constants have been exposed:

  • PASSWORD_ARGON2I
  • PASSWORD_ARGON2_DEFAULT_MEMORY_COST
  • PASSWORD_ARGON2_DEFAULT_TIME_COST
  • PASSWORD_ARGON2_DEFAULT_THREADS

Extended string types for PDO

PDO's string type has been extended to support the national character type when emulating prepares. This has been done with the following constants:

  • PDO::PARAM_STR_NATL
  • PDO::PARAM_STR_CHAR
  • PDO::ATTR_DEFAULT_STR_PARAM

These constants are utilised by bitwise OR'ing them with PDO::PARAM_STR:

<?php

$db
->quote('über'PDO::PARAM_STR PDO::PARAM_STR_NATL);

Additional emulated prepares debugging information for PDO

The PDOStatement::debugDumpParams() method has been updated to include the SQL being sent to the DB, where the full, raw query (including the replaced placeholders with their bounded values) will be shown. This has been added to aid with debugging emulated prepares (and so it will only be available when emulated prepares are turned on).

Support for extended operations in LDAP

Support for EXOP has been added to the LDAP extension. This has been done by exposing the following functions and constants:

Address Information additions to the Sockets extension

The sockets extension now has the ability to lookup address information, as well as connect to it, bind to it, and explain it. The following four functions have been added for this:

Parameter type widening

Parameter types from overridden methods and from interface implementations may now be omitted. This is still in compliance with LSP, since parameters types are contravariant.

<?php

interface A
{
    public function 
Test(array $input);
}

class 
implements A
{
    public function 
Test($input){} // type omitted for $input
}

Allow a trailing comma for grouped namespaces

A trailing comma can now be added to the group-use syntax introduced in PHP 7.0.

<?php

use Foo\Bar\{
    
Foo,
    
Bar,
    
Baz,
};

proc_nice() support on Windows

The proc_nice() function is now supported on Windows.

pack() and unpack() endian support

The pack() and unpack() functions now support float and double in both little and big endian.

Enhancements to the EXIF extension

The EXIF extension has been updated to support a much larger range of formats. This means that their format specific tags are now properly translated when parsing images with the exif_read_data() function. The following new formats are now supported:

  • Samsung
  • DJI
  • Panasonic
  • Sony
  • Pentax
  • Minolta
  • Sigma/Foveon
  • AGFA
  • Kyocera
  • Ricoh
  • Epson

The EXIF functions exif_read_data() and exif_thumbnail() now support passing streams as their first argument.

New features in PCRE

  • The J modifier for setting PCRE_DUPNAMES has been added.

SQLite3 allows writing BLOBs

SQLite3::openBlob() now allows to open BLOB fields in write mode; formerly only read mode was supported.

Oracle OCI8 Transparent Application Failover Callbacks

Support for Oracle Database Transparent Application Failover (TAF) callbacks has been added. TAF allows PHP OCI8 applications to automatically reconnect to a preconfigured database when a connection is broken. The new TAF callback support allows PHP applications to monitor and control reconnection during failover.

Enhancements to the ZIP extension

Read and write support for encrypted archives has been added (requires libzip 1.2.0).

The ZipArchive class now implements the Countable interface.

The zip:// stream now accepts a 'password' context option.

PHP 7.1

New features

Nullable types

Type declarations for parameters and return values can now be marked as nullable by prefixing the type name with a question mark. This signifies that as well as the specified type, null can be passed as an argument, or returned as a value, respectively.

<?php

function testReturn(): ?string
{
    return 
'elePHPant';
}

var_dump(testReturn());

function 
testReturn(): ?string
{
    return 
null;
}

var_dump(testReturn());

function 
test(?string $name)
{
    
var_dump($name);
}

test('elePHPant');
test(null);
test();

The above example will output:

string(10) "elePHPant"
NULL
string(10) "elePHPant"
NULL
Uncaught Error: Too few arguments to function test(), 0 passed in...

Void functions

A void return type has been introduced. Functions declared with void as their return type must either omit their return statement altogether, or use an empty return statement. null is not a valid return value for a void function.

<?php
function swap(&$left, &$right): void
{
    if (
$left === $right) {
        return;
    }

    
$tmp $left;
    
$left $right;
    
$right $tmp;
}

$a 1;
$b 2;
var_dump(swap($a$b), $a$b);

The above example will output:

null
int(2)
int(1)

Attempting to use a void function's return value simply evaluates to null, with no warnings emitted. The reason for this is because warnings would implicate the use of generic higher order functions.

Symmetric array destructuring

The shorthand array syntax ([]) may now be used to destructure arrays for assignments (including within foreach), as an alternative to the existing list() syntax, which is still supported.

<?php
$data 
= [
    [
1'Tom'],
    [
2'Fred'],
];

// list() style
list($id1$name1) = $data[0];

// [] style
[$id1$name1] = $data[0];

// list() style
foreach ($data as list($id$name)) {
    
// logic here with $id and $name
}

// [] style
foreach ($data as [$id$name]) {
    
// logic here with $id and $name
}

Class constant visibility

Support for specifying the visibility of class constants has been added.

<?php
class ConstDemo
{
    const 
PUBLIC_CONST_A 1;
    public const 
PUBLIC_CONST_B 2;
    protected const 
PROTECTED_CONST 3;
    private const 
PRIVATE_CONST 4;
}

iterable pseudo-type

A new pseudo-type (similar to callable) called iterable has been introduced. It may be used in parameter and return types, where it accepts either arrays or objects that implement the Traversable interface. With respect to subtyping, parameter types of child classes may broaden a parent's declaration of array or Traversable to iterable. With return types, child classes may narrow a parent's return type of iterable to array or an object that implements Traversable.

<?php
function iterator(iterable $iter)
{
    foreach (
$iter as $val) {
        
//
    
}
}

Multi catch exception handling

Multiple exceptions per catch block may now be specified using the pipe character (|). This is useful for when different exceptions from different class hierarchies are handled the same.

<?php
try {
    
// some code
} catch (FirstException SecondException $e) {
    
// handle first and second exceptions
}

Support for keys in list()

You can now specify keys in list(), or its new shorthand [] syntax. This enables destructuring of arrays with non-integer or non-sequential keys.

<?php
$data 
= [
    [
"id" => 1"name" => 'Tom'],
    [
"id" => 2"name" => 'Fred'],
];

// list() style
list("id" => $id1"name" => $name1) = $data[0];

// [] style
["id" => $id1"name" => $name1] = $data[0];

// list() style
foreach ($data as list("id" => $id"name" => $name)) {
    
// logic here with $id and $name
}

// [] style
foreach ($data as ["id" => $id"name" => $name]) {
    
// logic here with $id and $name
}

Support for negative string offsets

Support for negative string offsets has been added to the string manipulation functions accepting offsets, as well as to string indexing with [] or {}. In such cases, a negative offset is interpreted as being an offset from the end of the string.

<?php
var_dump
("abcdef"[-2]);
var_dump(strpos("aabbcc""b", -3));

The above example will output:

string (1) "e"
int(3)

Negative string and array offsets are now also supported in the simple variable parsing syntax inside of strings.

<?php
$string 
'bar';
echo 
"The last character of '$string' is '$string[-1]'.\n";
?>

The above example will output:

The last character of 'bar' is 'r'.

Support for AEAD in ext/openssl

Support for AEAD (modes GCM and CCM) have been added by extending the openssl_encrypt() and openssl_decrypt() functions with additional parameters.

Convert callables to Closures with Closure::fromCallable()

A new static method has been introduced to the Closure class to allow for callables to be easily converted into Closure objects.

<?php
class Test
{
    public function 
exposeFunction()
    {
        return 
Closure::fromCallable([$this'privateFunction']);
    }

    private function 
privateFunction($param)
    {
        
var_dump($param);
    }
}

$privFunc = (new Test)->exposeFunction();
$privFunc('some value');

The above example will output:

string(10) "some value"

Asynchronous signal handling

A new function called pcntl_async_signals() has been introduced to enable asynchronous signal handling without using ticks (which introduce a lot of overhead).

<?php
pcntl_async_signals
(true); // turn on async signals

pcntl_signal(SIGHUP,  function($sig) {
    echo 
"SIGHUP\n";
});

posix_kill(posix_getpid(), SIGHUP);

The above example will output:

SIGHUP

HTTP/2 server push support in ext/curl

Support for server push has been added to the CURL extension (requires version 7.46 and above). This can be leveraged through the curl_multi_setopt() function with the new CURLMOPT_PUSHFUNCTION constant. The constants CURL_PUSH_OK and CURL_PUSH_DENY have also been added so that the execution of the server push callback can either be approved or denied.

Stream Context Options

The tcp_nodelay stream context option has been added.

PHP 7.0

New features

Scalar type declarations

Scalar type declarations come in two flavours: coercive (default) and strict. The following types for parameters can now be enforced (either coercively or strictly): strings (string), integers (int), floating-point numbers (float), and booleans (bool). They augment the other types introduced in PHP 5: class names, interfaces, array and callable.

<?php
// Coercive mode
function sumOfInts(int ...$ints)
{
    return 
array_sum($ints);
}

var_dump(sumOfInts(2'3'4.1));

The above example will output:

int(9)

To enable strict mode, a single declare directive must be placed at the top of the file. This means that the strictness of typing for scalars is configured on a per-file basis. This directive not only affects the type declarations of parameters, but also a function's return type (see return type declarations, built-in PHP functions, and functions from loaded extensions.

Full documentation and examples of scalar type declarations can be found in the type declaration reference.

Return type declarations

PHP 7 adds support for return type declarations. Similarly to argument type declarations, return type declarations specify the type of the value that will be returned from a function. The same types are available for return type declarations as are available for argument type declarations.

<?php

function arraysSum(array ...$arrays): array
{
    return 
array_map(function(array $array): int {
        return 
array_sum($array);
    }, 
$arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));

The above example will output:

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

Full documentation and examples of return type declarations can be found in the return type declarations. reference.

Null coalescing operator

The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not null; otherwise it returns its second operand.

<?php
// Fetches the value of $_GET['user'] and returns 'nobody'
// if it does not exist.
$username $_GET['user'] ?? 'nobody';
// This is equivalent to:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// Coalescing can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

Spaceship operator

The spaceship operator is used for comparing two expressions. It returns -1, 0 or 1 when $a is respectively less than, equal to, or greater than $b. Comparisons are performed according to PHP's usual type comparison rules.

<?php
// Integers
echo <=> 1// 0
echo <=> 2// -1
echo <=> 1// 1

// Floats
echo 1.5 <=> 1.5// 0
echo 1.5 <=> 2.5// -1
echo 2.5 <=> 1.5// 1
 
// Strings
echo "a" <=> "a"// 0
echo "a" <=> "b"// -1
echo "b" <=> "a"// 1
?>

Constant arrays using define()

Array constants can now be defined with define(). In PHP 5.6, they could only be defined with const.

<?php
define
('ANIMALS', [
    
'dog',
    
'cat',
    
'bird'
]);

echo 
ANIMALS[1]; // outputs "cat"
?>

Anonymous classes

Support for anonymous classes has been added via new class. These can be used in place of full class definitions for throwaway objects:

<?php
interface Logger {
    public function 
log(string $msg);
}

class 
Application {
    private 
$logger;

    public function 
getLogger(): Logger {
         return 
$this->logger;
    }

    public function 
setLogger(Logger $logger) {
         
$this->logger $logger;
    }
}

$app = new Application;
$app->setLogger(new class implements Logger {
    public function 
log(string $msg) {
        echo 
$msg;
    }
});

var_dump($app->getLogger());
?>

The above example will output:

object(class@anonymous)#2 (0) {
}

Full documentation can be found in the anonymous class reference.

Unicode codepoint escape syntax

This takes a Unicode codepoint in hexadecimal form, and outputs that codepoint in UTF-8 to a double-quoted string or a heredoc. Any valid codepoint is accepted, with leading 0's being optional.

echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";

The above example will output:

ª
ª (same as before but with optional leading 0's)
香

Closure::call()

Closure::call() is a more performant, shorthand way of temporarily binding an object scope to a closure and invoking it.

<?php
class {private $x 1;}

// Pre PHP 7 code
$getX = function() {return $this->x;};
$getXCB $getX->bindTo(new A'A'); // intermediate closure
echo $getXCB();

// PHP 7+ code
$getX = function() {return $this->x;};
echo 
$getX->call(new A);

The above example will output:

1
1

Filtered unserialize()

This feature seeks to provide better security when unserializing objects on untrusted data. It prevents possible code injections by enabling the developer to whitelist classes that can be unserialized.

<?php

// converts all objects into __PHP_Incomplete_Class object
$data unserialize($foo, ["allowed_classes" => false]);

// converts all objects into __PHP_Incomplete_Class object except those of MyClass and MyClass2
$data unserialize($foo, ["allowed_classes" => ["MyClass""MyClass2"]]);

// default behaviour (same as omitting the second argument) that accepts all classes
$data unserialize($foo, ["allowed_classes" => true]);

IntlChar

The new IntlChar class seeks to expose additional ICU functionality. The class itself defines a number of static methods and constants that can be used to manipulate unicode characters.

<?php

printf
('%x'IntlChar::CODEPOINT_MAX);
echo 
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

The above example will output:

10ffff
COMMERCIAL AT
bool(true)

In order to use this class, the Intl extension must be installed.

Expectations

Expectations are a backwards compatible enhancement to the older assert() function. They allow for zero-cost assertions in production code, and provide the ability to throw custom exceptions when the assertion fails.

While the old API continues to be maintained for compatibility, assert() is now a language construct, allowing the first parameter to be an expression rather than just a string to be evaluated or a bool value to be tested.

<?php
ini_set
('assert.exception'1);

class 
CustomError extends AssertionError {}

assert(false, new CustomError('Some error message'));
?>

The above example will output:

Fatal error: Uncaught CustomError: Some error message

Full details on this feature, including how to configure it in both development and production environments, can be found in the expectations section of the assert() reference.

Group use declarations

Classes, functions and constants being imported from the same namespace can now be grouped together in a single use statement.

<?php
// Pre PHP 7 code
use some\namespace\ClassA;
use 
some\namespace\ClassB;
use 
some\namespace\ClassC as C;

use function 
some\namespace\fn_a;
use function 
some\namespace\fn_b;
use function 
some\namespace\fn_c;

use const 
some\namespace\ConstA;
use const 
some\namespace\ConstB;
use const 
some\namespace\ConstC;

// PHP 7+ code
use some\namespace\{ClassAClassBClassC as C};
use function 
some\namespace\{fn_afn_bfn_c};
use const 
some\namespace\{ConstAConstBConstC};
?>

Generator Return Expressions

This feature builds upon the generator functionality introduced into PHP 5.5. It enables for a return statement to be used within a generator to enable for a final expression to be returned (return by reference is not allowed). This value can be fetched using the new Generator::getReturn() method, which may only be used once the generator has finished yielding values.

<?php

$gen 
= (function() {
    yield 
1;
    yield 
2;

    return 
3;
})();

foreach (
$gen as $val) {
    echo 
$valPHP_EOL;
}

echo 
$gen->getReturn(), PHP_EOL;

The above example will output:

1
2
3

Being able to explicitly return a final value from a generator is a handy ability to have. This is because it enables for a final value to be returned by a generator (from perhaps some form of coroutine computation) that can be specifically handled by the client code executing the generator. This is far simpler than forcing the client code to firstly check whether the final value has been yielded, and then if so, to handle that value specifically.

Generator delegation

Generators can now delegate to another generator, Traversable object or array automatically, without needing to write boilerplate in the outermost generator by using the yield from construct.

<?php
function gen()
{
    yield 
1;
    yield 
2;
    yield from 
gen2();
}

function 
gen2()
{
    yield 
3;
    yield 
4;
}

foreach (
gen() as $val)
{
    echo 
$valPHP_EOL;
}
?>

The above example will output:

1
2
3
4

Integer division with intdiv()

The new intdiv() function performs an integer division of its operands and returns it.

<?php
var_dump
(intdiv(103));
?>

The above example will output:

int(3)

Session options

session_start() now accepts an array of options that override the session configuration directives normally set in php.ini.

These options have also been expanded to support session.lazy_write, which is on by default and causes PHP to only overwrite any session file if the session data has changed, and read_and_close, which is an option that can only be passed to session_start() to indicate that the session data should be read and then the session should immediately be closed unchanged.

For example, to set session.cache_limiter to private and immediately close the session after reading it:

<?php
session_start
([
    
'cache_limiter' => 'private',
    
'read_and_close' => true,
]);
?>

preg_replace_callback_array()

The new preg_replace_callback_array() function enables code to be written more cleanly when using the preg_replace_callback() function. Prior to PHP 7, callbacks that needed to be executed per regular expression required the callback function to be polluted with lots of branching.

Now, callbacks can be registered to each regular expression using an associative array, where the key is a regular expression and the value is a callback.

CSPRNG Functions

Two new functions have been added to generate cryptographically secure integers and strings in a cross platform way: random_bytes() and random_int().

list() can always unpack objects implementing ArrayAccess

Previously, list() was not guaranteed to operate correctly with objects implementing ArrayAccess. This has been fixed.

Other Features

  • Class member access on cloning has been added, e.g. (clone $foo)->bar().

PHP 5.6

New features

Constant expressions

It is now possible to provide a scalar expression involving numeric and string literals and/or constants in contexts where PHP previously expected a static value, such as constant and property declarations and default function arguments.

<?php
const ONE 1;
const 
TWO ONE 2;

class 
{
    const 
THREE TWO 1;
    const 
ONE_THIRD ONE self::THREE;
    const 
SENTENCE 'The value of THREE is '.self::THREE;

    public function 
f($a ONE self::THREE) {
        return 
$a;
    }
}

echo (new 
C)->f()."\n";
echo 
C::SENTENCE;
?>

The above example will output:

4
The value of THREE is 3

It is also now possible to define a constant array using the const keyword:

<?php
const ARR = ['a''b'];

echo 
ARR[0];
?>

The above example will output:

a

Variadic functions via ...

Variadic functions can now be implemented using the ... operator, instead of relying on func_get_args().

<?php
function f($req$opt null, ...$params) {
    
// $params is an array containing the remaining arguments.
    
printf('$req: %d; $opt: %d; number of params: %d'."\n",
           
$req$optcount($params));
}

f(1);
f(12);
f(123);
f(1234);
f(12345);
?>

The above example will output:

$req: 1; $opt: 0; number of params: 0
$req: 1; $opt: 2; number of params: 0
$req: 1; $opt: 2; number of params: 1
$req: 1; $opt: 2; number of params: 2
$req: 1; $opt: 2; number of params: 3

Argument unpacking via ...

Arrays and Traversable objects can be unpacked into argument lists when calling functions by using the ... operator. This is also known as the splat operator in other languages, including Ruby.

<?php
function add($a$b$c) {
    return 
$a $b $c;
}

$operators = [23];
echo 
add(1, ...$operators);
?>

The above example will output:

6

Exponentiation via **

A right associative ** operator has been added to support exponentiation, along with a **= shorthand assignment operator.

<?php
printf
("2 ** 3 ==      %d\n"** 3);
printf("2 ** 3 ** 2 == %d\n"** ** 2);

$a 2;
$a **= 3;
printf("a ==           %d\n"$a);
?>

The above example will output:

2 ** 3 ==      8
2 ** 3 ** 2 == 512
a ==           8

use function and use const

The use operator has been extended to support importing functions and constants in addition to classes. This is achieved via the use function and use const constructs, respectively.

<?php
namespace Name\Space {
    const 
FOO 42;
    function 
f() { echo __FUNCTION__."\n"; }
}

namespace {
    use const 
Name\Space\FOO;
    use function 
Name\Space\f;

    echo 
FOO."\n";
    
f();
}
?>

The above example will output:

42
Name\Space\f

phpdbg

PHP now includes an interactive debugger called phpdbg implemented as a SAPI module. For more information, please visit the phpdbg documentation.

Default character encoding

default_charset is now used as the default character set for the htmlentities(), html_entity_decode() and htmlspecialchars() functions. Note that if the (now deprecated) iconv and mbstring encoding settings are set, they will take precedence over default_charset for iconv and mbstring functions, respectively.

The default value for this setting is UTF-8.

php://input is reusable

php://input may now be reopened and read as many times as required. This work has also resulted in a major reduction in the amount of memory required to deal with POST data.

Large file uploads

Files larger than 2 gigabytes in size are now accepted.

GMP supports operator overloading

GMP objects now support operator overloading and casting to scalar types. This allows for more expressive code using GMP:

<?php
$a 
gmp_init(42);
$b gmp_init(17);

if (
version_compare(PHP_VERSION'5.6''<')) {
    echo 
gmp_intval(gmp_add($a$b)), PHP_EOL;
    echo 
gmp_intval(gmp_add($a17)), PHP_EOL;
    echo 
gmp_intval(gmp_add(42$b)), PHP_EOL;
} else {
    echo 
$a $bPHP_EOL;
    echo 
$a 17PHP_EOL;
    echo 
42 $bPHP_EOL;
}
?>

The above example will output:

59
59
59

hash_equals() for timing attack safe string comparison

The hash_equals() function has been added to compare two strings in constant time. This should be used to mitigate timing attacks; for instance, when testing crypt() password hashes (assuming that you are unable to use password_hash() and password_verify(), which aren't susceptible to timing attacks).

<?php
$expected  
crypt('12345''$2a$07$usesomesillystringforsalt$');
$correct   crypt('12345''$2a$07$usesomesillystringforsalt$');
$incorrect crypt('1234',  '$2a$07$usesomesillystringforsalt$');

var_dump(hash_equals($expected$correct));
var_dump(hash_equals($expected$incorrect));
?>

The above example will output:

bool(true)
bool(false)

__debugInfo()

The __debugInfo() magic method has been added to allow objects to change the properties and values that are shown when the object is output using var_dump().

<?php
class {
    private 
$prop;

    public function 
__construct($val) {
        
$this->prop $val;
    }

    public function 
__debugInfo() {
        return [
            
'propSquared' => $this->prop ** 2,
        ];
    }
}

var_dump(new C(42));
?>

The above example will output:

object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}

gost-crypto hash algorithm

The gost-crypto hash algorithm has been added. This implements the GOST hash function using the CryptoPro S-box tables as specified by » RFC 4357, section 11.2.

SSL/TLS improvements

A wide range of improvements have been made to the SSL/TLS support in PHP 5.6. These include enabling peer verification by default, supporting certificate fingerprint matching, mitigating against TLS renegotiation attacks, and many new SSL context options to allow more fine grained control over protocol and verification settings when using encrypted streams.

These changes are described in more detail in the OpenSSL changes in PHP 5.6.x section of this migration guide.

pgsql async support

The pgsql extension now supports asynchronous connections and queries, thereby enabling non-blocking behaviour when interacting with PostgreSQL databases. Asynchronous connections may be established via the PGSQL_CONNECT_ASYNC constant, and the new pg_connect_poll(), pg_socket(), pg_consume_input() and pg_flush() functions may be used to handle asynchronous connections and queries.

PHP 5.5

New features

Generators added

Support for generators has been added via the yield keyword. Generators provide an easy way to implement simple iterators without the overhead or complexity of implementing a class that implements the Iterator interface.

A simple example that reimplements the range() function as a generator (at least for positive step values):

<?php
function xrange($start$limit$step 1) {
    for (
$i $start$i <= $limit$i += $step) {
        yield 
$i;
    }
}

echo 
'Single digit odd numbers: ';

/*
 * Note that an array is never created or returned,
 * which saves memory.
 */
foreach (xrange(192) as $number) {
    echo 
"$number ";
}

echo 
"\n";
?>

The above example will output:

Single digit odd numbers: 1 3 5 7 9 

finally keyword added

try-catch blocks now support a finally block for code that should be run regardless of whether an exception has been thrown or not.

New password hashing API

A new password hashing API that makes it easier to securely hash and manage passwords using the same underlying library as crypt() in PHP has been added. See the documentation for password_hash() for more detail.

foreach now supports list()

The foreach control structure now supports unpacking nested arrays into separate variables via the list() construct. For example:

<?php
$array 
= [
    [
12],
    [
34],
];

foreach (
$array as list($a$b)) {
    echo 
"A: $a; B: $b\n";
}
?>

The above example will output:

A: 1; B: 2
A: 3; B: 4

Further documentation is available on the foreach manual page.

empty() supports arbitrary expressions

Passing an arbitrary expression instead of a variable to empty() is now supported. For example:

<?php
function always_false() {
    return 
false;
}

if (empty(
always_false())) {
    echo 
"This will be printed.\n";
}

if (empty(
true)) {
    echo 
"This will not be printed.\n";
}
?>

The above example will output:

This will be printed.

array and string literal dereferencing

Array and string literals can now be dereferenced directly to access individual elements and characters:

<?php
echo 'Array dereferencing: ';
echo [
123][0];
echo 
"\n";

echo 
'String dereferencing: ';
echo 
'PHP'[0];
echo 
"\n";
?>

The above example will output:

Array dereferencing: 1
String dereferencing: P

Class name resolution via ::class

It is possible to use ClassName::class to get a fully qualified name of class ClassName. For example:

<?php
namespace Name\Space;
class 
ClassName {}

echo 
ClassName::class;

echo 
"\n";
?>

The above example will output:

Name\Space\ClassName

OPcache extension added

The Zend Optimiser+ opcode cache has been added to PHP as the new OPcache extension. OPcache improves PHP performance by storing precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request. See the installation instructions for more detail on enabling and using OPcache.

foreach now supports non-scalar keys

foreach now supports keys of any type. While non-scalar keys cannot occur in native PHP arrays, it is possible for Iterator::key() to return a value of any type, and this will now be handled correctly.

Apache 2.4 handler supported on Windows

The Apache 2.4 handler SAPI is now supported on Windows.

Improvements to GD

Various improvements have been made to the GD extension, these include:

PHP 5.4

New features

PHP 5.4.0 offers a wide range of new features:

  • Support for traits has been added.
  • Short array syntax has been added, e.g. $a = [1, 2, 3, 4]; or $a = ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4];.
  • Function array dereferencing has been added, e.g. foo()[0].
  • Closures now support $this.
  • <?= is now always available, regardless of the short_open_tag php.ini option.
  • Class member access on instantiation has been added, e.g. (new Foo)->bar().
  • Class::{expr}() syntax is now supported.
  • Binary number format has been added, e.g. 0b001001101.
  • Improved parse error messages and improved incompatible arguments warnings.
  • The session extension can now track the upload progress of files.
  • Built-in development web server in CLI mode.
  • The GD extension now supports reading and writing of WebP images via imagecreatefromwebp() and imagewebp(), respectively.

PHP 5.3

New features

PHP 5.3.0 offers a wide range of new features:

  • Support for namespaces has been added.
  • Support for Late Static Bindings has been added.
  • Support for jump labels (limited goto) has been added.
  • Support for native Closures (Lambda/Anonymous functions) has been added.
  • There are two new magic methods, __callStatic() and __invoke().
  • Nowdoc syntax is now supported, similar to Heredoc syntax, but with single quotes.
  • It is now possible to use Heredocs to initialize static variables and class properties/constants.
  • Heredocs may now be declared using double quotes, complementing the Nowdoc syntax.
  • Constants can now be declared outside a class using the const keyword.
  • The ternary operator now has a shorthand form: ?:.
  • The HTTP stream wrapper now considers all status codes from 200 to 399 to be successful.
  • Dynamic access to static methods is now possible:
    <?php
    class {
       public static 
    $foo 123;
    }

    $a "C";
    echo 
    $a::$foo;
    ?>

    The above example will output:

    123
    
  • Exceptions can now be nested:
    <?php
    class MyCustomException extends Exception {}

    try {
        throw new 
    MyCustomException("Exceptional"112);
    } catch (
    Exception $e) {
        
    /* Note the use of the third parameter to pass $e
         * into the RuntimeException. */
        
    throw new RuntimeException("Rethrowing"911$e);
    }
    ?>
  • A garbage collector for circular references has been added, and is enabled by default.
  • The mail() function now supports logging of sent email via the mail.log configuration directive. (Note: This only applies to email sent through this function.)

PHP 8.2

New Global Constants

COM

  • DISP_E_PARAMNOTFOUND
  • LOCALE_NEUTRAL

cURL

  • CURLALTSVC_H1 (libcurl >= 7.64.1)
  • CURLALTSVC_H2 (libcurl >= 7.64.1)
  • CURLALTSVC_H3 (libcurl >= 7.64.1)
  • CURLALTSVC_READONLYFILE (libcurl >= 7.64.1)
  • CURLAUTH_AWS_SIGV4 (libcurl >= 7.75.0)
  • CURLE_PROXY (libcurl >= 7.73.0)
  • CURLFTPMETHOD_DEFAULT
  • CURLHSTS_ENABLE (libcurl >= 7.74.0)
  • CURLHSTS_READONLYFILE (libcurl >= 7.74.0)
  • CURLINFO_PROXY_ERROR (libcurl >= 7.73.0)
  • CURLINFO_REFERER (libcurl >= 7.76.0)
  • CURLINFO_RETRY_AFTER (libcurl >= 7.66.0)
  • CURLMOPT_MAX_CONCURRENT_STREAMS (libcurl >= 7.67.0)
  • CURLOPT_ALTSVC_CTRL (libcurl >= 7.64.1)
  • CURLOPT_ALTSVC (libcurl >= 7.64.1)
  • CURLOPT_AWS_SIGV4 (libcurl >= 7.75.0)
  • CURLOPT_CAINFO_BLOB (libcurl >= 7.77.0)
  • CURLOPT_DOH_SSL_VERIFYHOST (libcurl >= 7.76.0)
  • CURLOPT_DOH_SSL_VERIFYPEER (libcurl >= 7.76.0)
  • CURLOPT_DOH_SSL_VERIFYSTATUS (libcurl >= 7.76.0)
  • CURLOPT_HSTS_CTRL (libcurl >= 7.74.0)
  • CURLOPT_HSTS (libcurl >= 7.74.0)
  • CURLOPT_MAIL_RCPT_ALLLOWFAILS (libcurl >= 7.69.0)
  • CURLOPT_MAXAGE_CONN (libcurl >= 7.65.0)
  • CURLOPT_MAXFILESIZE_LARGE
  • CURLOPT_MAXLIFETIME_CONN (libcurl >= 7.80.0)
  • CURLOPT_PROXY_CAINFO_BLOB (libcurl >= 7.77.0)
  • CURLOPT_SASL_AUTHZID (libcurl >= 7.66.0)
  • CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (libcurl >= 7.80.0)
  • CURLOPT_SSL_EC_CURVES (libcurl >= 7.73.0)
  • CURLOPT_UPKEEP_INTERVAL_MS (libcurl >= 7.62.0)
  • CURLOPT_UPLOAD_BUFFERSIZE (libcurl >= 7.62.0)
  • CURLOPT_XFERINFOFUNCTION (libcurl >= 7.32.0)
  • CURLPROTO_MQTT (libcurl >= 7.71.0)
  • CURLPX_BAD_ADDRESS_TYPE (libcurl >= 7.73.0)
  • CURLPX_BAD_VERSION (libcurl >= 7.73.0)
  • CURLPX_CLOSED (libcurl >= 7.73.0)
  • CURLPX_GSSAPI (libcurl >= 7.73.0)
  • CURLPX_GSSAPI_PERMSG (libcurl >= 7.73.0)
  • CURLPX_GSSAPI_PROTECTION (libcurl >= 7.73.0)
  • CURLPX_IDENTD_DIFFER (libcurl >= 7.73.0)
  • CURLPX_IDENTD (libcurl >= 7.73.0)
  • CURLPX_LONG_HOSTNAME (libcurl >= 7.73.0)
  • CURLPX_LONG_PASSWD (libcurl >= 7.73.0)
  • CURLPX_LONG_USER (libcurl >= 7.73.0)
  • CURLPX_NO_AUTH (libcurl >= 7.73.0)
  • CURLPX_OK (libcurl >= 7.73.0)
  • CURLPX_RECV_ADDRESS (libcurl >= 7.73.0)
  • CURLPX_RECV_AUTH (libcurl >= 7.73.0)
  • CURLPX_RECV_CONNECT (libcurl >= 7.73.0)
  • CURLPX_RECV_REQACK (libcurl >= 7.73.0)
  • CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED (libcurl >= 7.73.0)
  • CURLPX_REPLY_COMMAND_NOT_SUPPORTED (libcurl >= 7.73.0)
  • CURLPX_REPLY_CONNECTION_REFUSED (libcurl >= 7.73.0)
  • CURLPX_REPLY_GENERAL_SERVER_FAILURE (libcurl >= 7.73.0)
  • CURLPX_REPLY_HOST_UNREACHABLE (libcurl >= 7.73.0)
  • CURLPX_REPLY_NETWORK_UNREACHABLE (libcurl >= 7.73.0)
  • CURLPX_REPLY_NOT_ALLOWED (libcurl >= 7.73.0)
  • CURLPX_REPLY_TTL_EXPIRED (libcurl >= 7.73.0)
  • CURLPX_REPLY_UNASSIGNED (libcurl >= 7.73.0)
  • CURLPX_REQUEST_FAILED (libcurl >= 7.73.0)
  • CURLPX_RESOLVE_HOST (libcurl >= 7.73.0)
  • CURLPX_SEND_AUTH (libcurl >= 7.73.0)
  • CURLPX_SEND_CONNECT (libcurl >= 7.73.0)
  • CURLPX_SEND_REQUEST (libcurl >= 7.73.0)
  • CURLPX_UNKNOWN_FAIL (libcurl >= 7.73.0)
  • CURLPX_UNKNOWN_MODE (libcurl >= 7.73.0)
  • CURLPX_USER_REJECTED (libcurl >= 7.73.0)
  • CURLSSLOPT_AUTO_CLIENT_CERT (libcurl >= 7.77.0)
  • CURLSSLOPT_NATIVE_CA (libcurl >= 7.71.0)
  • CURLSSLOPT_NO_PARTIALCHAIN (libcurl >= 7.68.0)
  • CURLSSLOPT_REVOKE_BEST_EFFORT (libcurl >= 7.70.0)
  • CURL_VERSION_GSASL (libcurl >= 7.76.0)
  • CURL_VERSION_HSTS (libcurl >= 7.74.0)
  • CURL_VERSION_HTTP3 (libcurl >= 7.66.0)
  • CURL_VERSION_UNICODE (libcurl >= 7.72.0)
  • CURL_VERSION_ZSTD (libcurl >= 7.72.0)

DBA

  • DBA_LMDB_USE_SUB_DIR
  • DBA_LMDB_NO_SUB_DIR

Filter

  • FILTER_FLAG_GLOBAL_RANGE

Sockets

The following socket options are now defined if they are supported:

  • SO_INCOMING_CPU
  • SO_MEMINFO
  • SO_RTABLE (OpenBSD)
  • TCP_KEEPALIVE (MacOS)
  • TCP_KEEPCNT (Linux, others)
  • TCP_KEEPIDLE (Linux, others)
  • TCP_KEEPINTVL (Linux, others)
  • TCP_NOTSENT_LOWAT
  • LOCAL_CREDS_PERSISTENT (FreeBSD)
  • SCM_CREDS2 (FreeBSD)
  • LOCAL_CREDS (NetBSD)
  • SO_BPF_EXTENSIONS
  • SO_SETFIB
  • TCP_CONGESTION (Linux, FreeBSD)
  • SO_ZEROCOPY (Linux)
  • MSG_ZEROCOPY (Linux)

PHP 8.1

New Global Constants

cURL

  • CURLOPT_DOH_URL
  • CURLOPT_ISSUERCERT_BLOB
  • CURLOPT_PROXY_ISSUERCERT
  • CURLOPT_PROXY_ISSUERCERT_BLOB
  • CURLOPT_PROXY_SSLCERT_BLOB
  • CURLOPT_PROXY_SSLKEY_BLOB
  • CURLOPT_SSLCERT_BLOB
  • CURLOPT_SSLKEY_BLOB

GD

  • IMG_AVIF
  • IMG_WEBP_LOSSLESS

MySQLi

  • MYSQLI_REFRESH_REPLICA

    This constant has been added as a replacement for MYSQLI_REFRESH_SLAVE, in line with an upstream change in MySQL. The old constant is still available for backwards-compatibility reasons, but may be deprecated/removed in the future.

PCNTL

  • PRIO_DARWIN_BG
  • PRIO_DARWIN_THREAD

POSIX

  • POSIX_RLIMIT_KQUEUES
  • POSIX_RLIMIT_NPTS

Sockets

The following socket options are now defined if they are supported:

  • SO_ACCEPTFILTER
  • SO_DONTTRUNC
  • SO_WANTMORE
  • SO_MARK
  • TCP_DEFER_ACCEPT

Sodium

  • SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES
  • SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES
  • SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES
  • SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES
  • SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES
  • SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES
  • SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES
  • SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES

Tokenizer

  • T_READONLY

PHP 7.4

New Global Constants

PHP Core

  • PHP_WINDOWS_EVENT_CTRL_C
  • PHP_WINDOWS_EVENT_CTRL_BREAK

Multibyte String

  • MB_ONIGURUMA_VERSION

Sockets

Added the following FreeBSD-specific socket options:

  • SO_LABEL
  • SO_PEERLABEL
  • SO_LISTENQLIMIT
  • SO_LISTENQLEN
  • SO_USER_COOKIE

Tidy

  • TIDY_TAG_ARTICLE
  • TIDY_TAG_ASIDE
  • TIDY_TAG_AUDIO
  • TIDY_TAG_BDI
  • TIDY_TAG_CANVAS
  • TIDY_TAG_COMMAND
  • TIDY_TAG_DATALIST
  • TIDY_TAG_DETAILS
  • TIDY_TAG_DIALOG
  • TIDY_TAG_FIGCAPTION
  • TIDY_TAG_FIGURE
  • TIDY_TAG_FOOTER
  • TIDY_TAG_HEADER
  • TIDY_TAG_HGROUP
  • TIDY_TAG_MAIN
  • TIDY_TAG_MARK
  • TIDY_TAG_MENUITEM
  • TIDY_TAG_METER
  • TIDY_TAG_NAV
  • TIDY_TAG_OUTPUT
  • TIDY_TAG_PROGRESS
  • TIDY_TAG_SECTION
  • TIDY_TAG_SOURCE
  • TIDY_TAG_SUMMARY
  • TIDY_TAG_TEMPLATE
  • TIDY_TAG_TIME
  • TIDY_TAG_TRACK
  • TIDY_TAG_VIDEO

PHP 7.3

New Global Constants

PHP Core

  • PASSWORD_ARGON2ID

Client URL Library

  • CURLAUTH_BEARER
  • CURLAUTH_GSSAPI
  • CURLE_WEIRD_SERVER_REPLY
  • CURLINFO_APPCONNECT_TIME_T
  • CURLINFO_CONNECT_TIME_T
  • CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
  • CURLINFO_CONTENT_LENGTH_UPLOAD_T
  • CURLINFO_FILETIME_T
  • CURLINFO_HTTP_VERSION
  • CURLINFO_NAMELOOKUP_TIME_T
  • CURLINFO_PRETRANSFER_TIME_T
  • CURLINFO_PROTOCOL
  • CURLINFO_PROXY_SSL_VERIFYRESULT
  • CURLINFO_REDIRECT_TIME_T
  • CURLINFO_SCHEME
  • CURLINFO_SIZE_DOWNLOAD_T
  • CURLINFO_SIZE_UPLOAD_T
  • CURLINFO_SPEED_DOWNLOAD_T
  • CURLINFO_SPEED_UPLOAD_T
  • CURLINFO_STARTTRANSFER_TIME_T
  • CURLINFO_TOTAL_TIME_T
  • CURL_LOCK_DATA_CONNECT
  • CURL_LOCK_DATA_PSL
  • CURL_MAX_READ_SIZE
  • CURLOPT_ABSTRACT_UNIX_SOCKET
  • CURLOPT_DISALLOW_USERNAME_IN_URL
  • CURLOPT_DNS_SHUFFLE_ADDRESSES
  • CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS
  • CURLOPT_HAPROXYPROTOCOL
  • CURLOPT_KEEP_SENDING_ON_ERROR
  • CURLOPT_PRE_PROXY
  • CURLOPT_PROXY_CAINFO
  • CURLOPT_PROXY_CAPATH
  • CURLOPT_PROXY_CRLFILE
  • CURLOPT_PROXY_KEYPASSWD
  • CURLOPT_PROXY_PINNEDPUBLICKEY
  • CURLOPT_PROXY_SSLCERT
  • CURLOPT_PROXY_SSLCERTTYPE
  • CURLOPT_PROXY_SSL_CIPHER_LIST
  • CURLOPT_PROXY_SSLKEY
  • CURLOPT_PROXY_SSLKEYTYPE
  • CURLOPT_PROXY_SSL_OPTIONS
  • CURLOPT_PROXY_SSL_VERIFYHOST
  • CURLOPT_PROXY_SSL_VERIFYPEER
  • CURLOPT_PROXY_SSLVERSION
  • CURLOPT_PROXY_TLS13_CIPHERS
  • CURLOPT_PROXY_TLSAUTH_PASSWORD
  • CURLOPT_PROXY_TLSAUTH_TYPE
  • CURLOPT_PROXY_TLSAUTH_USERNAME
  • CURLOPT_REQUEST_TARGET
  • CURLOPT_SOCKS5_AUTH
  • CURLOPT_SSH_COMPRESSION
  • CURLOPT_SUPPRESS_CONNECT_HEADERS
  • CURLOPT_TIMEVALUE_LARGE
  • CURLOPT_TLS13_CIPHERS
  • CURLPROXY_HTTPS
  • CURLSSH_AUTH_GSSAPI
  • CURL_SSLVERSION_MAX_DEFAULT
  • CURL_SSLVERSION_MAX_NONE
  • CURL_SSLVERSION_MAX_TLSv1_0
  • CURL_SSLVERSION_MAX_TLSv1_1
  • CURL_SSLVERSION_MAX_TLSv1_2
  • CURL_SSLVERSION_MAX_TLSv1_3
  • CURL_SSLVERSION_TLSv1_3
  • CURL_VERSION_ALTSVC (as of PHP 7.3.6)
  • CURL_VERSION_ASYNCHDNS
  • CURL_VERSION_BROTLI
  • CURL_VERSION_CONV
  • CURL_VERSION_CURLDEBUG (as of PHP 7.3.6)
  • CURL_VERSION_DEBUG
  • CURL_VERSION_GSSAPI
  • CURL_VERSION_GSSNEGOTIATE
  • CURL_VERSION_HTTPS_PROXY
  • CURL_VERSION_IDN
  • CURL_VERSION_LARGEFILE
  • CURL_VERSION_MULTI_SSL
  • CURL_VERSION_NTLM
  • CURL_VERSION_NTLM_WB
  • CURL_VERSION_PSL (as of PHP 7.3.6)
  • CURL_VERSION_SPNEGO
  • CURL_VERSION_SSPI
  • CURL_VERSION_TLSAUTH_SRP

Data Filtering

  • FILTER_SANITIZE_ADD_SLASHES

JavaScript Object Notation

  • JSON_THROW_ON_ERROR

Lightweight Directory Access Protocol

  • LDAP_CONTROL_ASSERT
  • LDAP_CONTROL_MANAGEDSAIT
  • LDAP_CONTROL_PROXY_AUTHZ
  • LDAP_CONTROL_SUBENTRIES
  • LDAP_CONTROL_VALUESRETURNFILTER
  • LDAP_CONTROL_PRE_READ
  • LDAP_CONTROL_POST_READ
  • LDAP_CONTROL_SORTREQUEST
  • LDAP_CONTROL_SORTRESPONSE
  • LDAP_CONTROL_PAGEDRESULTS
  • LDAP_CONTROL_AUTHZID_REQUEST
  • LDAP_CONTROL_AUTHZID_RESPONSE
  • LDAP_CONTROL_SYNC
  • LDAP_CONTROL_SYNC_STATE
  • LDAP_CONTROL_SYNC_DONE
  • LDAP_CONTROL_DONTUSECOPY
  • LDAP_CONTROL_PASSWORDPOLICYREQUEST
  • LDAP_CONTROL_PASSWORDPOLICYRESPONSE
  • LDAP_CONTROL_X_INCREMENTAL_VALUES
  • LDAP_CONTROL_X_DOMAIN_SCOPE
  • LDAP_CONTROL_X_PERMISSIVE_MODIFY
  • LDAP_CONTROL_X_SEARCH_OPTIONS
  • LDAP_CONTROL_X_TREE_DELETE
  • LDAP_CONTROL_X_EXTENDED_DN
  • LDAP_CONTROL_VLVREQUEST
  • LDAP_CONTROL_VLVRESPONSE

Multibyte String

  • MB_CASE_FOLD
  • MB_CASE_LOWER_SIMPLE
  • MB_CASE_UPPER_SIMPLE
  • MB_CASE_TITLE_SIMPLE
  • MB_CASE_FOLD_SIMPLE

OpenSSL

  • STREAM_CRYPTO_PROTO_SSLv3
  • STREAM_CRYPTO_PROTO_TLSv1_0
  • STREAM_CRYPTO_PROTO_TLSv1_1
  • STREAM_CRYPTO_PROTO_TLSv1_2

PostgreSQL

  • PGSQL_DIAG_SCHEMA_NAME
  • PGSQL_DIAG_TABLE_NAME
  • PGSQL_DIAG_COLUMN_NAME
  • PGSQL_DIAG_DATATYPE_NAME
  • PGSQL_DIAG_CONSTRAINT_NAME
  • PGSQL_DIAG_SEVERITY_NONLOCALIZED

PHP 7.2

New global constants

JSON

  • JSON_INVALID_UTF8_IGNORE
  • JSON_INVALID_UTF8_SUBSTITUTE

Sodium

PHP 7.1

New global constants

Core Predefined Constants

  • PHP_FD_SETSIZE

CURL

  • CURLMOPT_PUSHFUNCTION
  • CURL_PUSH_OK
  • CURL_PUSH_DENY

Data Filtering

  • FILTER_FLAG_EMAIL_UNICODE

Image Processing and GD

  • IMAGETYPE_WEBP

JSON

  • JSON_UNESCAPED_LINE_TERMINATORS

LDAP

  • LDAP_OPT_X_SASL_NOCANON
  • LDAP_OPT_X_SASL_USERNAME
  • LDAP_OPT_X_TLS_CACERTDIR
  • LDAP_OPT_X_TLS_CACERTFILE
  • LDAP_OPT_X_TLS_CERTFILE
  • LDAP_OPT_X_TLS_CIPHER_SUITE
  • LDAP_OPT_X_TLS_KEYFILE
  • LDAP_OPT_X_TLS_RANDOM_FILE
  • LDAP_OPT_X_TLS_CRLCHECK
  • LDAP_OPT_X_TLS_CRL_NONE
  • LDAP_OPT_X_TLS_CRL_PEER
  • LDAP_OPT_X_TLS_CRL_ALL
  • LDAP_OPT_X_TLS_DHFILE
  • LDAP_OPT_X_TLS_CRLFILE
  • LDAP_OPT_X_TLS_PROTOCOL_MIN
  • LDAP_OPT_X_TLS_PROTOCOL_SSL2
  • LDAP_OPT_X_TLS_PROTOCOL_SSL3
  • LDAP_OPT_X_TLS_PROTOCOL_TLS1_0
  • LDAP_OPT_X_TLS_PROTOCOL_TLS1_1
  • LDAP_OPT_X_TLS_PROTOCOL_TLS1_2
  • LDAP_OPT_X_TLS_PACKAGE
  • LDAP_OPT_X_KEEPALIVE_IDLE
  • LDAP_OPT_X_KEEPALIVE_PROBES
  • LDAP_OPT_X_KEEPALIVE_INTERVAL

PostgreSQL

  • PGSQL_NOTICE_LAST
  • PGSQL_NOTICE_ALL
  • PGSQL_NOTICE_CLEAR

SPL

  • MT_RAND_PHP

PHP 7.0

New Global Constants

GD

  • IMG_WEBP (as of PHP 7.0.10)

JSON

  • JSON_ERROR_INVALID_PROPERTY_NAME
  • JSON_ERROR_UTF16

LibXML

  • LIBXML_BIGLINES

PCRE

  • PREG_JIT_STACKLIMIT_ERROR

POSIX

  • POSIX_RLIMIT_AS
  • POSIX_RLIMIT_CORE
  • POSIX_RLIMIT_CPU
  • POSIX_RLIMIT_DATA
  • POSIX_RLIMIT_FSIZE
  • POSIX_RLIMIT_LOCKS
  • POSIX_RLIMIT_MEMLOCK
  • POSIX_RLIMIT_MSGQUEUE
  • POSIX_RLIMIT_NICE
  • POSIX_RLIMIT_NOFILE
  • POSIX_RLIMIT_NPROC
  • POSIX_RLIMIT_RSS
  • POSIX_RLIMIT_RTPRIO
  • POSIX_RLIMIT_RTTIME
  • POSIX_RLIMIT_SIGPENDING
  • POSIX_RLIMIT_STACK
  • POSIX_RLIMIT_INFINITY

Zlib

  • ZLIB_ENCODING_RAW
  • ZLIB_ENCODING_DEFLATE
  • ZLIB_ENCODING_GZIP
  • ZLIB_FILTERED
  • ZLIB_HUFFMAN_ONLY
  • ZLIB_FIXED
  • ZLIB_RLE
  • ZLIB_DEFAULT_STRATEGY
  • ZLIB_BLOCK
  • ZLIB_FINISH
  • ZLIB_FULL_FLUSH
  • ZLIB_NO_FLUSH
  • ZLIB_PARTIAL_FLUSH
  • ZLIB_SYNC_FLUSH

PHP 5.6

New global constants

GD

  • IMG_WEBP (as of PHP 5.6.25)

LDAP

  • LDAP_ESCAPE_DN
  • LDAP_ESCAPE_FILTER

OpenSSL

  • OPENSSL_DEFAULT_STREAM_CIPHERS
  • STREAM_CRYPTO_METHOD_ANY_CLIENT
  • STREAM_CRYPTO_METHOD_ANY_SERVER
  • STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
  • STREAM_CRYPTO_METHOD_TLSv1_0_SERVER
  • STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
  • STREAM_CRYPTO_METHOD_TLSv1_1_SERVER
  • STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
  • STREAM_CRYPTO_METHOD_TLSv1_2_SERVER

PostgreSQL

  • PGSQL_CONNECT_ASYNC
  • PGSQL_CONNECTION_AUTH_OK
  • PGSQL_CONNECTION_AWAITING_RESPONSE
  • PGSQL_CONNECTION_MADE
  • PGSQL_CONNECTION_SETENV
  • PGSQL_CONNECTION_SSL_STARTUP
  • PGSQL_CONNECTION_STARTED
  • PGSQL_DML_ESCAPE
  • PGSQL_POLLING_ACTIVE
  • PGSQL_POLLING_FAILED
  • PGSQL_POLLING_OK
  • PGSQL_POLLING_READING
  • PGSQL_POLLING_WRITING

PHP 8.2

Other Changes

Core changes

The iterable type is now a built-in compile time alias for array|Traversable. Error messages relating to iterable will therefore now use array|Traversable. Type Reflection is preserved for single iterable (and ?iterable) to produce a ReflectionNamedType with name iterable, however usage of iterable in union types will be converted to array|Traversable.

Changes in SAPI Modules

CLI

The STDOUT, STDERR and STDIN streams are no longer closed on resource destruction which is mostly when the CLI finishes. It is however still possible to explicitly close those streams using fclose() and similar.

Changed Functions

Core

The strcmp(), strcasecmp(), strncmp(), strncasecmp(), and substr_compare() functions, using binary safe string comparison now return -1, 0 and 1.

DBA

dba_open() and dba_popen() now have the following enforced signature:

dba_open(
    string $path,
    string $mode,
    ?string $handler = null,
    int $permission = 0644,
    int $map_size = 0,
    ?int $flags = null
): resource|false

dba_fetch()'s optional skip argument is now at the end in line with PHP userland semantics. Its signature is now:

dba_fetch(string|array $key, resource $handle, int $skip): string|false
The overloaded signature:
dba_fetch(string|array $key, int $skip, resource $handle): string|false
is still accepted, but it is recommended to use the new standard variant.

Random

random_bytes() and random_int() now throw a \Random\RandomException on CSPRNG failures. Previously a plain \Exception was thrown instead.

SPL

The iterator parameter of iterator_to_array() and iterator_count() is widened to iterable from Iterator, allowing arrays to be passed.

Other Changes to Extensions

Date

The properties of DatePeriod are now properly declared.

Intl

Instances of IntlBreakIterator, IntlRuleBasedBreakIterator, IntlCodePointBreakIterator, IntlPartsIterator, IntlCalendar, IntlCalendar, Collator, IntlIterator, UConverter, IntlDateFormatter, IntlDatePatternGenerator, MessageFormatter, ResourceBundle, Spoofchecker, IntlTimeZone, and Transliterator are no longer serializable. Previously, they could be serialized, but unserialization yielded unusable objects or failed.

MySQLi

The support for libmysql has been removed and it is no longer possible to compile mysqli with libmysql. From now on, the mysqli extension can be compiled only with mysqlnd. All libmysql features unavailable in mysqlnd have been removed:

OCI8

The minimum Oracle Client library version required is now 11.2.

PCRE

NUL characters (\0) in pattern strings are now supported.

Session

Trying to change the session.cookie_samesite INI directive while the session is active or output has already been sent will now fail and emit a warning. This aligns the behaviour with all other session INI settings.

SQLite3

sqlite3.defensive is now PHP_INI_USER.

Standard

getimagesize() now reports the actual image dimensions, bits and channels of AVIF images. Previously, the dimensions have been reported as 0x0, and bits and channels have not been reported at all.

Tidy

The properties of the tidy class are now properly declared. And those of the tidyNode class are now properly declared as readonly.

Zip

The Zip extension has been updated to version 1.20.0, which adds the following methods:

Changes to INI File Handling

Support for binary (0b/0B) and octal (0o/0O) prefixes has been added to integer INI settings. Integer INI settings that start with a zero (0) continue to be interpreted as an octal integer.

Parsing of some ill-formatted values will now trigger a warning when this was silently ignored before. For backwards compatibility, interpretation of these values has not changed. This affects the following settings:

PHP 8.1

Other Changes

Changes in SAPI Modules

CLI

Using -a without the readline extension will now result in an error. Previously, -a without readline had the same behavior as calling php without any arguments, apart from printing an additional "Interactive mode enabled" message. This mode was not interactive.

PHPDBG

Remote functionality from phpdbg has been removed.

Changed Functions

Core

The order of properties used in foreach, var_dump(), serialize(), object comparison, etc. was changed. Properties are now ordered naturally according to their declaration and inheritance. Properties declared in a base class are going to be before the child properties.

This order is consistent with internal layout of properties in zend_object structure and repeats the order in default_properties_table[] and properties_info_table[]. The old order was not documented and was caused by class inheritance implementation details.

Filter

The FILTER_FLAG_ALLOW_OCTAL flag of the FILTER_VALIDATE_INT filter now accept octal string with the leading octal prefix ("0o"/"0O").

GMP

All GMP functions now accept octal string with the leading octal prefix ("0o"/"0O").

PDO ODBC

PDO::getAttribute() with PDO::ATTR_SERVER_INFO and PDO::ATTR_SERVER_VERSION now return values instead of throwing PDOException.

Reflection

ReflectionProperty::setAccessible() and ReflectionMethod::setAccessible() no longer have an effect. Properties and methods are now always considered accessible via Reflection.

Standard

syslog() is now binary safe.

Other Changes to Extensions

GD

imagewebp() can now do lossless WebP encoding by passing IMG_WEBP_LOSSLESS as the quality.

This constant is only defined, if the used libgd supports lossless WebP encoding.

MySQLi

mysqli_stmt::next_result() and mysqli::fetch_all() are now available when linking against libmysqlclient.

OpenSSL

  • The OpenSSL extension now requires at least OpenSSL version 1.0.2.

  • OpenSSL 3.0 is now supported. Be aware that many ciphers are no longer enabled by default (part of the legacy provider), and that parameter validation (e.g. minimum key sizes) is stricter now.

Phar

  • SHA256 is now used by default for signatures.

  • Added support for OpenSSL_SHA256 and OpenSSL_SHA512 signatures.

SNMP

  • Added support for SHA256 and SHA512 for the security protocol.

Standard

--with-password-argon2 now uses pkg-config to detect libargon2. As such, an alternative libargon2 location should now be specified using PKG_CONFIG_PATH.

Changes to INI File Handling

  • The log_errors_max_len INI directive has been removed. It no longer had an effect since PHP 8.0.0.

  • A leading dollar in a quoted string can now be escaped: "\${" will now be interpreted as a string with contents ${.

  • Backslashes in double quoted strings are now more consistently treated as escape characters. Previously, "foo\\" followed by something other than a newline was not considered as a terminated string. It is now interpreted as a string with contents foo\. However, as an exception, the string "foo\" followed by a newline will continue to be treated as a valid string with contents foo\ rather than an unterminated string. This exception exists to support naive uses of Windows file paths such as "C:\foo\".

PHP 8.0

Other Changes

Changes in SAPI Modules

Apache2Handler

The PHP module has been renamed from php7_module to php_module.

Changed Functions

Reflection

ReflectionClass::getConstants() and ReflectionClass::getReflectionConstants() results can be now filtered via a new parameter filter. Three new constants were added to be used with it:

  • ReflectionClassConstant::IS_PUBLIC
  • ReflectionClassConstant::IS_PROTECTED
  • ReflectionClassConstant::IS_PRIVATE

Standard

The math functions abs(), ceil(), floor() and round() now properly heed the strict_types directive. Previously, they coerced the first argument even in strict type mode.

Zip

Other Changes to Extensions

CURL

  • The CURL extension now requires at least libcurl 7.29.0.

  • The deprecated parameter version of curl_version() has been removed.

Date and Time

DatePeriod now implements IteratorAggregate (instead of Traversable).

DOM

DOMNamedNodeMap and DOMNodeList now implement IteratorAggregate (instead of Traversable).

Intl

IntlBreakIterator and ResourceBundle now implement IteratorAggregate (instead of Traversable).

Enchant

The enchant extension now uses libenchant-2 by default when available. libenchant version 1 is still supported but is deprecated and could be removed in the future.

GD

JSON

The JSON extension cannot be disabled anymore and is always an integral part of any PHP build, similar to the date extension.

MBString

The Unicode data tables have been updated to version 13.0.0.

PDO

PDOStatement now implements IteratorAggregate (instead of Traversable).

LibXML

The minimum required libxml version is now 2.9.0. This means that external entity loading is now guaranteed to be disabled by default, and no extra steps need to be taken to protect against XXE attacks.

MySQLi / PDO MySQL

PGSQL / PDO PGSQL

The PGSQL and PDO PGSQL extensions now require at least libpq 9.1.

Readline

Calling readline_completion_function() before the interactive prompt starts (e.g. in auto_prepend_file) will now override the default interactive prompt completion function. Previously, readline_completion_function() only worked when called after starting the interactive prompt.

SimpleXML

SimpleXMLElement now implements RecursiveIterator and absorbed the functionality of SimpleXMLIterator. SimpleXMLIterator is an empty extension of SimpleXMLElement.

Changes to INI File Handling

  • com.dotnet_version is a new INI directive to choose the version of the .NET framework to use for dotnet objects.

  • zend.exception_string_param_max_len is a new INI directive to set the maximum string length in an argument of a stringified stack strace.

EBCDIC

EBCDIC targets are no longer supported, though it's unlikely that they were still working in the first place.

Performance

  • A Just-In-Time (JIT) compiler has been added to the opcache extension.

  • array_slice() on an array without gaps will no longer scan the whole array to find the start offset. This may significantly reduce the runtime of the function with large offsets and small lengths.

  • strtolower() now uses a SIMD implementation when using the "C" LC_CTYPE locale (which is the default).

PHP 7.4

Other Changes

Performance Improvements

PHP Core

A specialized VM opcode for the array_key_exists() function has been added, which improves performance of this function if it can be statically resolved. In namespaced code, this may require writing \array_key_exists() or explicitly importing the function.

Regular Expressions (Perl-Compatible)

When preg_match() in UTF-8 mode ("u" modifier) is repeatedly called on the same string (but possibly different offsets), it will only be checked for UTF-8 validity once.

Changes to INI File Handling

zend.exception_ignore_args is a new INI directive for including or excluding arguments from stack traces generated from exceptions.

opcache.preload_user is a new INI directive for specifying the user account under which preloading code is execute if it would otherwise be run as root (which is not allowed for security reasons).

Migration to pkg-config

A number of extensions have been migrated to exclusively use pkg-config for the detection of library dependencies. Generally, this means that instead of using --with-foo-dir=DIR or similar only --with-foo is used. Custom library paths can be specified either by adding additional directories to PKG_CONFIG_PATH or by explicitly specifying compilation options through FOO_CFLAGS and FOO_LIBS.

The following extensions and SAPIs are affected:

  • CURL:
    • --with-curl no longer accepts a directory.
  • Enchant:
    • --with-enchant no longer accepts a directory.
  • FPM:
    • --with-fpm-systemd now uses only pkg-config for libsystem checks. The libsystemd minimum required version is 209.
  • GD:
    • --with-gd becomes --enable-gd (whether to enable the extension at all) and --with-external-gd (to opt into using an external libgd, rather than the bundled one).
    • --with-png-dir has been removed. libpng is required.
    • --with-zlib-dir has been removed. zlib is required.
    • --with-freetype-dir becomes --with-freetype
    • --with-jpeg-dir becomes --with-jpeg
    • --with-webp-dir becomes --with-webp
    • --with-xpm-dir becomes --with-xpm
  • IMAP:
    • --with-kerberos-systemd no longer accepts a directory.
  • Intl:
    • --with-icu-dir has been removed. If --enable-intl is passed, then libicu is always required.
  • LDAP:
    • --with-ldap-sasl no longer accepts a directory.
  • Libxml:
    • --with-libxml-dir has been removed.
    • --enable-libxml becomes --with-libxml.
    • --with-libexpat-dir has been renamed to --with-expat and no longer accepts a directory.
  • Litespeed:
    • --with-litespeed becomes --enable-litespeed.
  • Mbstring:
    • --with-onig has been removed. Unless --disable-mbregex has been passed, libonig is required.
  • ODBC:
    • --with-iodbc no longer accepts a directory.
    • --with-unixODBC without a directory now uses pkg-config (preferred). Directory is still accepted for old versions without libodbc.pc.
  • OpenSSL:
    • --with-openssl no longer accepts a directory.
  • PCRE:
    • --with-pcre-regex has been removed. Instead --with-external-pcre is provided to opt into using an external PCRE library, rather than the bundled one.
  • PDO_SQLite:
    • --with-pdo-sqlite no longer accepts a directory.
  • Readline:
    • --with-libedit no longer accepts a directory.
  • Sodium:
    • --with-sodium no longer accepts a directory.
  • SQLite3:
    • --with-sqlite3 no longer accepts a directory.
  • XSL:
    • --with-xsl no longer accepts a directory.
  • Zip:
    • --with-libzip has been removed.
    • --enable-zip becomes --with-zip.

CSV escaping

fputcsv(), fgetcsv(), SplFileObject::fputcsv(), SplFileObject::fgetcsv(), and SplFileObject::setCsvControl() now accept an empty string as $escape argument, which disables the proprietary PHP escaping mechanism.

The behavior of str_getcsv() has been adjusted accordingly (formerly, an empty string was identical to using the default).

SplFileObject::getCsvControl() now may also return an empty string for the third array element, accordingly.

Data Filtering

The filter extension no longer exposes --with-pcre-dir for Unix builds and can now reliably be built as shared when using ./configure

GD

The behavior of imagecropauto() in the bundled libgd has been synced with that of system libgd:

  • IMG_CROP_DEFAULT is no longer falling back to IMG_CROP_SIDES
  • Threshold-cropping now uses the algorithm of system libgd

The default $mode parameter of imagecropauto() has been changed to IMG_CROP_DEFAULT; passing -1 is now deprecated.

imagescale() now supports aspect ratio preserving scaling to a fixed height by passing -1 as $new_width.

HASH Message Digest Framework

The hash extension cannot be disabled anymore and is always an integral part of any PHP build, similar to the date extension.

Intl

The intl extension now requires at least ICU 50.1.

ResourceBundle now implements Countable.

Lightweight Directory Access Protocol

Support for nsldap and umich_ldap has been removed.

Libxml

All libxml-based extensions now require libxml 2.7.6 or newer.

Multibyte String

The oniguruma library is no longer bundled with PHP, instead libonig needs to be available on the system. Alternatively --disable-mbregex can be used to disable the mbregex component.

OPcache

The --disable-opcache-file and --enable-opcache-file configure options have been removed in favor of the opcache.file_cache INI directive.

Password Hashing

The password_hash() and password_needs_rehash() functions now accept nullable string and int for $algo argument.

PEAR

Installation of PEAR (including PECL) is no longer enabled by default. It can be explicitly enabled using --with-pear. This option is deprecated and may be removed in the future.

Reflection

The numeric values of the modifier constants (IS_ABSTRACT, IS_DEPRECATED, IS_EXPLICIT_ABSTRACT, IS_FINAL, IS_IMPLICIT_ABSTRACT, IS_PRIVATE, IS_PROTECTED, IS_PUBLIC, and IS_STATIC) on the ReflectionClass, ReflectionFunction, ReflectionMethod, ReflectionObject, and ReflectionProperty classes have changed.

SimpleXML

SimpleXMLElement now implements Countable.

SQLite3

The bundled libsqlite has been removed. To build the SQLite3 extension a system libsqlite3 ≥ 3.7.4 is now required. To build the PDO_SQLite extension a system libsqlite3 ≥ 3.5.0 is now required.

Serialization and unserialization of SQLite3, SQLite3Stmt and SQLite3Result is now explicitly forbidden. Formerly, serialization of instances of these classes was possible, but unserialization yielded unusable objects.

The @param notation can now also be used to denote SQL query parameters.

Zip

The bundled libzip library has been removed. A system libzip >= 0.11 is now necessary to build the zip extension.

PHP 7.3

Other Changes

PHP Core

Set(raw)cookie accepts $option Argument

setcookie() and setrawcookie() now also support the following signature:

setcookie(string $name, string $value = "", array $options = []): bool
where $options is an associative array which may have any of the keys "expires", "path", "domain", "secure", "httponly" and "samesite".

New Syslog ini Directives

The following ini Directives have been added to customize logging, if error_log is set to syslog:

syslog.facility
Specifies what type of program is logging the message.
syslog.filter
Specifies the filter type to filter the logged messages, with the supported filter types - all, no-ctrl and ascii. Starting with PHP 7.3.8, raw is also available, restoring the way syslog behaved in previous PHP versions. This filter will also affect calls to syslog().
syslog.ident
Specifies the ident string which is prepended to every message.

Garbage Collection

The cyclic GC has been enhanced, which may result in considerable performance improvements.

Miscellaneous

var_export() now exports stdClass objects as an array cast to an object ((object) array( ... )