PHP 8.3

Other Changes

Core changes

FFI

FFI::load() is now allowed during preloading when opcache.preload_user is the current system user. Previously, calling FFI::load() was not possible during preloading if the opcache.preload_user directive was set.

FPM

FPM CLI test now fails if the socket path is longer than supported by OS.

Opcache

In the CLI and phpdbg SAPIs, preloading does not require the opcache.preload_user directive to be set anymore when running as root. In other SAPIs, this directive is required when running as root because preloading is done before the SAPI switches to an unprivileged user.

Streams

Blocking fread() on socket connection returns immediately if there are any buffered data instead of waiting for more data.

A memory stream no longer fails if the seek offset is past the end. Instead, the memory will be increased on the next write and the data between the old end and the offset is filled with zero bytes, similar to how files work.

stat() access operations like file_exists() and similar will now use real path instead of the actual stream path. This is consistent with stream opening.

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

gc_status() has added the following 8 fields:

  • "running" => bool
  • "protected" => bool
  • "full" => bool
  • "buffer_size" => int
  • "application_time" => float: Total application time, in seconds (including collector_time)
  • "collector_time" => float: Time spent collecting cycles, in seconds (including destructor_time and free_time)
  • "destructor_time" => float: Time spent executing destructors during cycle collection, in seconds
  • "free_time" => float: Time spent freeing values during cycle collection, in seconds

class_alias() now supports creating an alias of an internal class.

Setting open_basedir at runtime using ini_set('open_basedir', ...); no longer accepts paths containing the parent directory (..). Previously, only paths starting with .. were disallowed. This could easily be circumvented by prepending ./ to the path.

User exception handlers now catch exceptions during shutdown.

The resultant HTML of highlight_string() and highlight_file() has changed. Whitespace between outer HTML tags is removed. Newlines and spaces are no longer converted to HTML entities. The whole HTML is now wrapped in a

 tag. The outer 
    tag has been merged with the  tag.
   

Calendar

easter_date() now supports years from 1970 to 2,000,000,000 on 64-bit systems, previously it only supported years in the range from 1970 to 2037.

Curl

curl_getinfo() now supports two new constants: CURLINFO_CAPATH and CURLINFO_CAINFO. If option is null, the following two additional keys are present: "capath" and "cainfo".

DOM

Changed DOMCharacterData::appendData() tentative return type to true.

DOMDocument::loadHTML(), DOMDocument::loadHTMLFile(), and DOMDocument::loadXML() now have a tentative return type of bool. Previously, this was documented as having a return type of DOMDocument|bool, but, as of PHP 8.0.0, DOMDocument cannot be returned as it is no longer statically callable.

Gd

The signature of imagerotate() has changed. The $ignore_transparent parameter has been removed, as it was ignored since PHP 5.5.0.

Intl

datefmt_set_timezone() (and its alias IntlDateformatter::setTimeZone()) now returns true on success, previously null was returned.

IntlBreakiterator::setText() now returns false on failure, previously null was returned. It now returns true on success, previously null was returned.

IntlChar::enumCharNames() is now returning a boolean. Previously it returned null on success and false on failure.

IntlDateFormatter::__construct() throws an U_ILLEGAL_ARGUMENT_ERROR exception when an invalid locale had been set.

MBString

mb_strtolower() and mb_convert_case() implement conditional casing rules for the Greek letter sigma. For mb_convert_case(), conditional casing only applies to MB_CASE_LOWER and MB_CASE_TITLE modes, not to MB_CASE_LOWER_SIMPLE and MB_CASE_TITLE_SIMPLE.

mb_decode_mimeheader() interprets underscores in QPrint-encoded MIME encoded words as required by RFC 2047; they are converted to spaces. Underscores must be encoded as "=5F" in such MIME encoded words.

In rare cases, mb_encode_mimeheader() will transfer-encode its input string where it would pass it through as raw ASCII in PHP 8.2.

mb_encode_mimeheader() no longer drops NUL (zero) bytes when QPrint-encoding the input string. This previously caused strings in certain text encodings, especially UTF-16 and UTF-32, to be corrupted by mb_encode_mimeheader.

mb_detect_encoding()'s "non-strict" mode now behaves as described in the documentation. Previously, it would return false if the same byte (for example, the first byte) of the input string was invalid in all candidate encodings. More generally, it would eliminate candidate encodings from consideration when an invalid byte was seen, and if the same input byte eliminated all remaining encodings still under consideration, it would return false. On the other hand, if all candidate encodings but one were eliminated from consideration, it would return the last remaining one without regard for how many encoding errors might be encountered later in the string. This is different from the behavior described in the documentation, which says: "If strict is set to false, the closest matching encoding will be returned."

mysqli

mysqli_fetch_object() now raises a ValueError instead of an Exception when the $constructor_args argument is non empty with the class not having constructor.

mysqli_poll() now raises a ValueError when neither the $read nor the $error arguments are passed.

mysqli_field_seek() and mysqli_result::field_seek() now specify the return type as true instead of bool.

ODBC

odbc_autocommit() now accepts null for the $enable parameter. Passing null has the same behaviour as passing only 1 parameter, namely indicating if the autocommit feature is enabled or not.

PGSQL

pg_fetch_object() now raises a ValueError instead of an Exception when the $constructor_args argument is non empty with the class not having constructor.

pg_insert() now raises a ValueError instead of a E_WARNING when the table specified is invalid.

pg_insert() and pg_convert() raises a ValueError or a TypeError instead of a E_WARNING when the value/type of a field does not match properly with a PostgreSQL's type.

The $row parameter of pg_fetch_result(), pg_field_prtlen(), and pg_field_is_null() is now nullable.

Random

Changed mt_srand() and srand() to not check the number of arguments to determine whether a random seed should be used. Passing null will generate a random seed, 0 will use zero as the seed. The functions are now consistent with Random\Engine\Mt19937::__construct().

Reflection

Return type of ReflectionClass::getStaticProperties() is no longer nullable.

Standard

E_NOTICEs emitted by unserialize() have been promoted to E_WARNING.

unserialize() now emits a new E_WARNING if the input contains unconsumed bytes.

array_pad() is now only limited by the maximum number of elements an array can have. Before, it was only possible to add at most 1048576 elements at a time.

strtok() raises an E_WARNING in the case token is not provided when starting tokenization.

password_hash() will now chain the underlying Random\RandomException as the ValueError's $previous Exception when salt generation fails.

If using an array as the $command for proc_open(), it must now have at least one non empty element. Otherwise a ValueError is thrown.

proc_open() returns false if $command array is invalid command instead of resource object that produces warning later. This was already the case for Windows but it is now also the case if posix_spawn implementation is in use (most Linux, BSD and MacOS platforms). There are still some old platforms where this behavior is not changed as posix_spawn is not supported there.

array_sum() and array_product() now warn when values in the array cannot be converted to int/float. Previously arrays and objects where ignored whilst every other value was cast to int. Moreover, objects that define a numeric cast (e.g. GMP) are now casted instead of ignored.

The $decimal of number_format() now properly handles negative integers. Rounding with a negative value for $decimal means that $num is rounded to $decimals significant digits before the decimal point. Previously negative $decimals were silently ignored and the number got rounded to zero decimal places.

A new $before_needle argument has been added to strrchr(). It behaves like its counterpart in the strstr() or stristr() functions.

str_getcsv() and fgetcsv() now return an empty string instead of a string with a single null byte for the last field which only contains an unterminated enclosure.

Other Changes to Extensions

Core

Using the increment/decrement operators (++/--) on values of type bool now emit warnings. This is because it currently has no effect, but will behave like $bool += 1 in the future.

Using the decrement operator (--) on values of type null now emit warnings. This is because it currently has no effect, but will behave like $null -= 1 in the future.

Internal objects that implement an _IS_NUMBER cast but not a do_operator handler that overrides addition and subtraction now can be incremented and decrement as if one would do $o += 1 or $o -= 1

DOM

The DOM lifetime mechanism has been reworked such that implicitly removed nodes can still be fetched. Previously this resulted in an exception.

SQLite3

The SQLite3 class now throws SQLite3Exception (extends Exception) instead of Exception.

The SQLite error code is now passed in the exception error code instead of being included in the error message.

Changes to INI File Handling

  • The assert.* INI settings have been deprecated. This comprises the following INI settings:

    If the value of the setting is equal to the default value, no deprecation notice is emitted. The zend.assertions INI setting should be used instead.
  • zend.max_allowed_stack_size is a new INI directive to set the maximum allowed stack size. Possible values are 0 (detect the process or thread maximum stack size), -1 (no limit), or a positive number of bytes. The default is 0. When it is not possible to detect the process or thread maximum stack size, a known system default is used. Setting this value too high has the same effect as disabling the stack size limit. Fibers use fiber.stack_size as maximum allowed stack size. An Error is thrown when the process call stack exceeds zend.max_allowed_stack_size-zend.reserved_stack_size bytes, to prevent stack-overflow-induced segmentation faults, with the goal of making debugging easier. The stack size increases during uncontrolled recursions involving internal functions or the magic methods __toString(), __clone(), __sleep(), __destruct(). This is not related to stack buffer overflows, and is not a security feature.

  • zend.reserved_stack_size is a new INI directive to set the reserved stack size, in bytes. This is subtracted from the max allowed stack size, as a buffer, when checking the stack size.

Performance

DOM

Looping over a DOMNodeList now uses caching. Therefore requesting items no longer takes quadratic time by default.

Getting text content from nodes now avoids an allocation, resulting in a performance gain.

DOMChildNode::remove() now runs in O(1) performance.

Standard

The file() flags error check is now about 7% faster.

SPL

RecursiveDirectoryIterator now performs less I/O when looping over a directory.

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.

The date format of sent cookies is now 'D, d M Y H:i:s \G\M\T'; previously it was 'D, d-M-Y H:i:s T'.

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, 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 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( ... )), rather than using the nonexistent method stdClass::__setState().

debug_zval_dump() was changed to display recursive arrays and objects in the same way as var_dump(). Now, it doesn't display them twice.

array_push() and array_unshift() can now also be called with a single argument, which is particularly convenient wrt. the spread operator.

Interactive PHP Debugger

The unused constants PHPDBG_FILE, PHPDBG_METHOD, PHPDBG_LINENO and PHPDBG_FUNC have been removed.

FastCGI Process Manager

The getallheaders() function is now also available.

Client URL Library

libcurl ≥ 7.15.5 is now required.

Data Filtering

FILTER_VALIDATE_FLOAT now also supports a thousand option, which defines the set of allowed thousand separator chars. The default ("',.") is fully backward compatible with former PHP versions.

FILTER_SANITIZE_ADD_SLASHES has been added as an alias of the magic_quotes filter (FILTER_SANITIZE_MAGIC_QUOTES). The magic_quotes filter is subject to removal in future versions of PHP.

FTP

The default transfer mode has been changed to binary.

Internationalization Functions

Normalizer::NONE is deprecated, when PHP is linked with ICU ≥ 56.

Introduced Normalizer::FORM_KC_CF as Normalizer::normalize() argument for NFKC_Casefold normalization; available when linked with ICU ≥ 56.

JavaScript Object Notation

A new flag has been added, JSON_THROW_ON_ERROR, which can be used with json_decode() or json_encode() and causes these functions to throw the new JsonException upon an error, instead of setting the global error state that is retrieved with json_last_error() and json_last_error_msg(). JSON_PARTIAL_OUTPUT_ON_ERROR takes precedence over JSON_THROW_ON_ERROR.

Multibyte String

The configuration option --with-libmbfl is no longer available.

ODBC (Unified)

Support for ODBCRouter and Birdstep including the birdstep.max_links ini directive has been removed.

OPcache

The opcache.inherited_hack ini directive has been removed. The value has already been ignored since PHP 5.3.0.

OpenSSL

The min_proto_version and max_proto_version ssl stream options as well as related constants for possible TLS protocol values have been added.

Regular Expressions (Perl-Compatible)

The PCRE extension has been upgraded to PCRE2, which may cause minor behavioral changes (for instance, character ranges in classes are now more strictly interpreted), and augments the existing regular expression syntax.

preg_quote() now also escapes the '#' character.

Microsoft SQL Server and Sybase Functions (PDO_DBLIB)

The attribute PDO::DBLIB_ATTR_SKIP_EMPTY_ROWSETS to enable automatic skipping of empty rowsets has been added.

The PDO::DBLIB_ATTR_TDS_VERSION attribute which exposes the TDS version has been added.

DATETIME2 columns are now treated like DATETIME columns.

SQLite Functions (PDO_SQLITE)

SQLite3 databases can now be opened in read-only mode by setting the new PDO::SQLITE_ATTR_OPEN_FLAGS attribute to PDO::SQLITE_OPEN_READONLY.

Session Handling

session_set_cookie_params() now also supports the following signature:

session_set_cookie_params(array $options): bool
where $options is an associative array which may have any of the keys "lifetime", "path", "domain", "secure", "httponly" and "samesite". Accordingly, the return value of session_get_cookie_params() now also has an element with the key "samesite". Furthermore, the new session.cookie_samesite ini option to set the default of the SameSite directive for cookies has been added. It defaults to "" (empty string), so no SameSite directive is set. Can be set to "Lax" or "Strict", which sets the respective SameSite directive.

Tidy

Building against » tidyp is now also supported transparently. Since tidyp offers no API to get the release date, tidy_get_release() and tidy::getRelease() return 'unknown' in this case.

XML Parser

The return value of the xml_set_external_entity_ref_handler() callback is no longer ignored if the extension has been built against libxml. Formerly, the return value has been ignored, and parsing did never stop.

Zip

Building against the bundled libzip is discouraged, but still possible by adding --without-libzip to the configuration.

Zlib Compression

The zlib/level context option for the compress.zlib wrapper to facilitate setting the desired compression level has been added.

PHP 7.2

Other changes

Moving of utf8_encode() and utf8_decode()

The utf8_encode() and utf8_decode() functions have now been moved to the standard extension as string functions, whereas before the XML extension was required for them to be available.

Changes to mail() and mb_send_mail()

The $additional_headers parameter of mail() and mb_send_mail() now also accepts an array instead of a string.

LMDB support

The DBA extension now has support for LMDB.

Changes to the PHP build system

  • Unix: Autoconf 2.64 or greater is now required to build PHP.
  • Unix: --with-pdo-oci configure argument no longer needs the version number of the Oracle Instant Client.
  • Unix: --enable-gd-native-ttf configure argument has been removed. This was not used since PHP 5.5.0.
  • Windows: --with-config-profile configure argument has been added. This can be used to save specific configures, much like the magical config.nice.bat file.

Changes to GD

  • imageantialias() is now also available if compiled with a system libgd.
  • imagegd() stores truecolor images as real truecolor images. Formerly, they have been converted to palette.

Moving MCrypt to PECL

The MCrypt extension has now been moved out of the core to PECL. Given the mcrypt library has not seen any updates since 2007, its usage is highly discouraged. Instead, either the OpenSSL or Sodium extension should be used.

session_module_name()

Passing "user" to session_module_name() now raises an error of level E_RECOVERABLE_ERROR. Formerly, this has been silently ignored.

PHP 7.1

Other changes

Notices and warnings on arithmetic with invalid strings

New E_WARNING and E_NOTICE errors have been introduced when invalid strings are coerced using operators expecting numbers (+ - * / ** % << >> | & ^) or their assignment equivalents. An E_NOTICE is emitted when the string begins with a numeric value but contains trailing non-numeric characters, and an E_WARNING is emitted when the string does not contain a numeric value.

'1b' + 'something';

The above example will output:

Notice: A non well formed numeric value encountered in %s on line %d
Warning: A non-numeric value encountered in %s on line %d

Warn on octal escape sequence overflow

Previously, 3-octet octal string escape sequences would overflow silently. Now, they will still overflow, but E_WARNING will be emitted.

var_dump("\500");

The above example will output:

Warning: Octal escape sequence overflow \500 is greater than \377 in %s on line %d
string(1) "@"

Inconsistency fixes to $this

Whilst $this is considered a special variable in PHP, it lacked proper checks to ensure it wasn't used as a variable name or reassigned. This has now been rectified to ensure that $this cannot be a user-defined variable, reassigned to a different value, or be globalised.

Session ID generation without hashing

Session IDs will no longer be hashed upon generation. With this change brings about the removal of the following four ini settings:

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

And the addition of the following two ini settings:

  • session.sid_length - defines the length of the session ID, defaulting to 32 characters for backwards compatibility)
  • session.sid_bits_per_character - defines the number of bits to be stored per character (i.e. increases the range of characters that can be used in the session ID), defaulting to 4 for backwards compatibility

Changes to INI file handling

precision

If the value is set to -1, then the dtoa mode 0 is used. The default value is still 14.

serialize_precision

If the value is set to -1, then the dtoa mode 0 is used. The value -1 is now used by default.

gd.jpeg_ignore_warning

The default of this php.ini setting has been changed to 1, so by default libjpeg warnings are ignored.

opcache.enable_cli

The default of this php.ini setting has been changed to 1 (enabled) in PHP 7.1.2, and back to 0 (disabled) in PHP 7.1.7.

Session ID generation with a CSPRNG only

Session IDs will now only be generated with a CSPRNG.

More informative TypeError messages when null is allowed

TypeError exceptions for arg_info type checks will now provide more informative error messages. If the parameter type or return type accepts null (by either having a default value of null or being a nullable type), then the error message will now mention this with a message of "must be ... or null" or "must ... or be null."

PHP 7.0

Other Changes

Loosening Reserved Word Restrictions

Globally reserved words as property, constant, and method names within classes, interfaces, and traits are now allowed. This reduces the surface of BC breaks when new keywords are introduced and avoids naming restrictions on APIs.

This is particularly useful when creating internal DSLs with fluent interfaces:

// 'new', 'private', and 'for' were previously unusable
Project::new('Project Name')->private()->for('purpose here')->with('username here');
?>

The only limitation is that the class keyword still cannot be used as a constant name, otherwise it would conflict with the class name resolution syntax (ClassName::class).

Removal of date.timezone Warning

Previously, a warning was emitted if the date.timezone INI setting had not been set prior to using any date- or time-based functions. Now, this warning has been removed (with date.timezone still defaulting to UTC).