PHP 8.1: What's New and Changed

Version StatusFuture Release

PHP 8.1 is currently in active development, and it will be released towards the end of year 2021.

Explicit Octal numeral notation

TypeNew Feature

PHP supports various numeral systems, including the default decimal (base-10), binary (base-2), octal (base-8), and hex (base-16).

Numeral systems apart from decimal are prefixed with their own prefix:

  • Hex with 0x prefix: e.g. 0x11 = 17
  • Binary with 0b prefix: e.g. 0b11 = 3
  • Octal with 0 prefix: e.g. 011 = 9

In PHP 8.1 and later, Octal numerals also support the 0o (zero, followed by o as in Oscar) prefix, which means octal numeric literals can be made more obvious and readable that they are indeed octal numerals. 0O (zero, followed by upper case O as in Oscar) is also supported.

Many programming languages use 0 prefix for octal numeric literals, just like PHP. However, many languages also support the explicit 0o notation and have been recommending the 0o.

echo 0xff; // 255
echo 0b111; // 7
echo 77; // 77
echo 077; // 63
echo 0o77; // 63, In PHP 8.1
echo 0O77; // 63, In PHP 8.1
077 === 63; // true
077 === 0o77; // true
077 === 0O77; // true

Further, the underscore numeric separators are supported in 0o/0O prefixed numeric literals as well:

echo 0o7716_1412; // 16573194

0 Prefix Is Not Changed

The existing 0 prefix is not deprecated, and continue function exactly the same.

The 0o/0O prefixes are supported in addition to the existing 0 prefix.

No Changes in Numeric Strings

Numeric strings, i.e. strings that contain a number, are not impacted by this change. "0o16" (as a string) will not be interpreted as a number, and does not return true for is_numeric function either.

echo "016"; // "016"
is_numeric("0o77"); // false
is_numeric("0b11"); // false
is_numeric("0x16"); // false

Note that "016" returns true for is_numeric, and it is not changed:

is_numeric("016"); // true

Backwards Compatibility Impact

The 0o and 0O prefixes are new prefixes, that were not supported in older PHP versions. Attempting to use them in older PHP versions result in a syntax error:

$value = 0o77;
Parse error: syntax error, unexpected identifier "o77" in ... on line ...

RFC Discussion Implementation

New `array_is_list` function

TypeNew Feature

PHP 8.1 brings a new function array_is_list, that returns whether a given array is an array with all sequential integers starting from 0.

In other words, this function returns true if the given array is semantic list of values; an array with all keys are integers, keys start from 0, with no gaps in between.

array_is_list function returns true on empty arrays as well.

array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list(['apple', 2, 3]); // true
array_is_list(['apple', 'orange']); // true
array_is_list([0 => 'apple', 'orange']); // true
array_is_list([0 => 'apple', 1 => 'orange']); // true

Any array with keys not starting from zero, or any array with not all keys are integers in sequential order evaluates to false:

// Key does not start with 0
array_is_list([1 => 'apple', 'orange']); // false

// Keys are not in order
array_is_list([1 => 'apple', 0 => 'orange']); // false

// Non-integer keys
array_is_list([0 => 'apple', 'foo' => 'bar']); false

// Non-sequential keys
array_is_list([0 => 'apple', 2 => 'bar']); false

array_is_list Function Synopsis

function array_is_list(array $array): bool {
}
  • array_is_list only accepts array parameters. Passing any other type will throw a TypeError exception.
  • array_is_list function does not accept iterable or other array-like class objects such as ArrayAccess, SPLFixedArray, etc.
  • array_is_list is declared in the global namespace.

Polyfill

array_is_list function can be trivially polyfilled with user-land PHP code:

function array_is_list(array $array): bool {
    if (empty($array)) {
        return true;
    }

    $current_key = 0;
    foreach ($array as $key => $noop) {
        if ($key !== $current_key) {
            return false;
        }
        ++$current_key;
    }

    return true;
}

Backwards Compatibility Impact

array_is_list is a new function added in PHP 8.1. Unless there is an existing function with the same name in global namespace, there should be no backwards-compatibility issues.

Further, array_is_list function can be back-ported to almost any PHP version.


RFC Discussion Implementation

Hash functions accept algorithm-specific `$options`

TypeNew Feature

Hash functions in PHP accept a new optional $options parameter in PHP 8.1, that can further specify custom algorithm-specific options.

The following functions accept the new $options parameter as their last parameter:

Function synopses

function hash(string $algo, string $data, bool $binary = false, array $options = []): string|false
function hash_file(string $algo, string $filename, bool $binary = false, array $options = []): string|false
function hash_init(string $algo, int $flags = 0, string $key = '', array $options = []): HashContext

Supported Custom Options

MurmurHash3 and xxHash algorithms support specifying custom options with the new $options parameter.

hash('murmur3f', 'php.watch'); // "ba0189037daec822d973d304602d44f0"
hash("murmur3f", "php.watch", options: ["seed" => 42]); // 0cafc26e49efe230cdbd109458fef893
hash("xxh3", "php.watch"); // "f406cee14d73b176"
hash("xxh3", "php.watch", options: ["seed" => 44]); // acb8c705fdcd579c

These snippet use named parameters introduced in PHP 8.0.

Backwards Compatibility Impact

The new $options parameter is a new parameter with a default value of an empty array, and will not cause any backwards-compatibility issues if the hash* functions are called with the additional $options parameter. PHP will silently ignore the additional parameters, but note that the output will be different across PHP versions without $options parameter support.

As of now, the only hashing algorithms that support custom options are MurmurHash3 and xxHash algorithms added in PHP 8.1.

Related Changes


Implementation

MurmurHash3 hash algorithm support

TypeNew Feature

PHP 8.1 adds support for MurmurHash hashing algorithm.

MurmurHash is a non-cryptographic hashing algorithm, and PHP 8.1 supports MurmurHash3 version of it. Following variants are supported:

  • murmur3a: 32-bit hash
  • murmur3c: 128-bit hash on x86 architecture
  • murmur3f: 128-bit hash on x64 architecture
hash('murmur3a', 'php.watch'); // "ac96fab7"
hash('murmur3c', 'php.watch'); // "6d0fe9c3f960dc75cf42632f3e78ffda"
hash('murmur3f', 'php.watch'); // "ba0189037daec822d973d304602d44f0"

MurmurHash is a streaming hash, which means the values can be updated in sequence without having to hash the input string as a whole.

$context = hash_init('murmur3f');
hash_update($context, 'php');
hash_update($context, '.');
hash_update($context, 'watch');
$hash = hash_final($context); // "ba0189037daec822d973d304602d44f0"

MurmurHash is not designed as a cryptographic hashing algorithm. For password hashing, use password_hash and its friends. Furthermore, none of the MurmurHash variants are allowed in hash_hmac function.

MurmurHash algorithm is faster than most of the hashing algorithms, and is one of the fastest non-cryptographic algorithms available in PHP, along with the new xxHash algorithms.

Algorithm PHP implementation speed (GB/s)
murmur3a 3.98
murmur3c 6.20
murmur3f 8.87
sha2-256 0.25
sha1-160 0.70
md5-128 0.77

The results above are an excerpt from PHP Hash Algorithm Benchmarks.

Custom Seed Options

PHP 8.1 supports specifying algorithm-specific options with the new $options parameter. Along with this, murmur* hashing algorithms accept additional options. The only supported option is seed value.

hash('murmur3f', 'php.watch'); // "ba0189037daec822d973d304602d44f0"
hash("murmur3f", "php.watch", false, ["seed" => 42]); // 0cafc26e49efe230cdbd109458fef893
hash("murmur3f", "php.watch", options: ["seed" => 42]); // 0cafc26e49efe230cdbd109458fef893

The third example uses named parameters introduced in PHP 8.0.

Backwards Compatibility Impact

MurmurHash is newly added to PHP 8.1, and due to current lack of a hash registry that supports adding custom hashing algorithms, producing MurmurHash hashes using the hash() function is not possible on older PHP versions.

On PHP 8.0, a ValueError exception will be thrown if attempted to hash('murmur...', '...'):

Fatal error: Uncaught ValueError: hash(): Argument #1 ($algo) must be a valid hashing algorithm in ...:...

On PHP versions prior to 8.0, a warning will be raised:

Warning: hash(): Unknown hashing algorithm: murmur3a in ... on line ...

Alternatives implementations include:

Related Changes


Implementation

xxHash hash algorithms support

TypeNew Feature

xxHash is an extremely fast hashing algorithm that is not designed for cryptographic purposes, but provides excellent randomness and dispersion of output, and uniqueness of to minimize collisions. Some xxHash variants in fact, are faster than the RAM throughput provided CPU cache is sufficient and fits.

PHP 8.1 adds support for xxHash algorithm in following variants:

  • xxh32: 32-bit hash output
  • xxh64: 64-bit hash output
  • xxh3: 64-bit hash output
  • xxh128: 128-bit hash output
hash('xxh32',  'php.watch'); // cb729dd1
hash('xxh32',  'php.watch'); // 9c823891d744a55e
hash('xxh3',   'php.watch'); // f406cee14d73b176
hash('xxh128', 'php.watch'); // 16c27099bd855aff3b3efe27980515ad

xxHash is a streaming hash, and can be used as such:

$context = hash_init('xxh3');
hash_update($context, 'php.');
hash_update($context, 'watch');
hash_final($context); // f406cee14d73b176

xxHash is not a cryptographic hashing algorithm. For password hashing, use password_hash and its friends. Furthermore, none of the xxHash variants are allowed in hash_hmac function.

In PHP 8.1, xxHash is the fastest hashing algorithm supported in PHP.

Algorithm PHP implementation speed (GB/s)
xxh3 15.19
xxh128 14.78
crc32c 14.12
xxh64 13.32
murmur3f 8.87
xxh32 7.47
sha2-256 0.25
sha1-160 0.70
md5-128 0.77

The results above are an excerpt from PHP Hash Algorithm Benchmarks.

Custom Seed Options

PHP 8.1 supports specifying algorithm-specific options with the new $options parameter. Along with this, xxh* hashing algorithms accept additional options. The only supported option is seed value.

hash('xxh3', 'php.watch'); // "f406cee14d73b176"

hash("xxh3", "php.watch", false, ["seed" => 42]); // de9956536d1e9543
hash("xxh3", "php.watch", options: ["seed" => 42]); // de9956536d1e9543

The third example uses named parameters introduced in PHP 8.0.

Backwards Compatibility Impact

xxHash is newly added to PHP 8.1, and older PHP versions will not be able to use xxHash algorithms via hash method.

Attempting to use xxHash algorithms in hash function results in a ValueError exception:

Fatal error: Uncaught ValueError: hash(): Argument #1 ($algo) must be a valid hashing algorithm in ...:...

On PHP versions prior to 8.0, a warning will be raised:

Warning: hash(): Unknown hashing algorithm: xxh3 in ... on line ...

Alternatives implementations include:

  • Megasaxon/php-xxhash - A PHP extension to add xxhash32 and xxhash64 for xxHash variants.
  • exussum12/xxhash - A pure-PHP implementation with FFI support. The pure-PHP implementation is ~600x slower than the native code, and the FFI implementation is only ~0.4x slower.

Related Changes


Implementation

Curl: DNS-over-HTTPS support

TypeNew Feature

In PHP 8.1, the Curl extension supports specifying a server for DNS-Over-HTTPS. It requires PHP to be compiled with libcurl version 7.62 or later.

Most of the current operating systems and distributions already support it, as they often include Curl 7.68 or later in Ubuntu 20.04, and other Linux/Windows/Mac OS operating systems.

A list of public DoH servers are available at Curl documentation.

CURLOPT_DOH_URL

The DNS-Over-HTTPS server URL is configured by setting the CURLOPT_DOH_URL option. This constant will only be available if the underlying libcurl version is >= 7.62.

$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_DOH_URL, 'https://dns.google/dns-query');
curl_exec($ch);

The behavior of the CURLOPT_DOH_URL is exactly same as the libcurl behavior; see CURLOPT_DOH_URL explained.

DoH Server URL Validation

The entered server URL is not validated at the time it is set. It is validated when the Curl request is executed. It must be an HTTPS URL.

If the provided DNS server is not a valid URL, or does not return a valid response, the request will fail. There is no fall-back to system DNS resolver, or a default DoH server configured in Curl.

Unset DoH Server URL

To unset a previously configured DoH server URL, set its value to null.

curl_setopt($ch, CURLOPT_DOH_URL, null);

Note that the Curl handle's DNS cache is independent of DoH servers. Setting a different DoH server URL, or unsetting it will not clear the DNS cache, and Curl will reuse values previously returned by system DNS resolver or any of the DoH servers configured.

Backwards Compatibility Impact

This feature is only available on PHP 8.1 and later, and it is not possible to back-port this feature.

It is possible to explicitly set an IP address to a host with CURLOPT_RESOLVE option, if the caller obtains the DNS information by using a DoH server with its own DNS querying.

Cross-version compatibility can be achieved by checking the CURLOPT_DOH_URL constant:

$ch = curl_init();
if (defined('CURLOPT_DOH_URL')) {
    curl_setopt($ch, CURLOPT_DOH_URL, 'https://dns.google/dns-query');
}
curl_exec($ch);

Implementation

GD Extension: Font identifiers are `\GdFont` class objects

TypeChange

Prior to PHP 8.1, the imageloadfont function from GD extension returned a font-identifier resource ID as an integer. In PHP 8.1 and later, the resource ID is migrated to a GdFont class instance.

All functions that previously accepted a resource ID from imageloadfont function now accept the new GdFont class objects, making this an opaque change.


Resource to Object Migration
PHP is gradually phasing out all resource types with class objects, and this migration is one step of the Resource to Object Migration plan.


imageloadfont function return value is changed from int to GdImage. This is different from other resource to object migrations that replaced a resource with a class instance.

gd resource for primitive GD images was migrated to GdImage class instances in PHP 8.0: GdImage class objects replace GD image resources

GdFont class synopsis

final class GdFont {}

Directly instantiating a GdFont instance is not allowed, and it is still required to use the imageloadfont:

$font = new GdFont();
PHP Error:  You cannot initialize a GdFont object except through helper functions in ... on line ...

GdFont class is also declared final, to prevent it from being extended with child classes, to reduce potential backwards-compatibility issues if the GdFont class structure changes in the future.

Backwards Compatibility Impact

Prior to this change in PHP 8.1, the GD Font resources were int values. All code with parameter/return/property type with this assumption now needs to accommodate GdFont class instances.

In PHP 8.0, Union Types can enforce this requirement.

- function addFont(int $gdfont){}
+ function addFont(int|GdFont $gdfont) {}

imageloadfont function continues to return false in case the font file could not be loaded, and a check against false value might be more readable and appropriate:

$font = imageloadfont($file);
- if (is_int($font)) {
+ if ($font !== false) {
 // 
}

Implementation

FTP Extension: Connection resources are `\FTPConnection` class objects

TypeChange

FTP connection resources from the ftp extension are migrated to class objects in PHP 8.1.

Prior to PHP 8.1, FTP connections created with ftp_connect(), and ftp_ssl_connect() functions returned a resource of type ftp. In PHP 8.1 and later, those functions return a FTPConnection class instance instead.

All functions that previously accepted resources accept the new type as well.

Resource to Object Migration
PHP is gradually phasing out all resource types with class objects, and this migration is one step of the Resource to Object Migration plan.

FTPConnection Class Synopsis

final class FTPConnection {}

Similar to other resource to object migrations, the new FTPConnection class is declared final to prevent them from extended (and reduce potential backwards-compatibility issues if PHP core changes the methods of the FTPConnection class).

Instantiating a new instance of FTPConnection is not allowed, and results in an \Error Exception.

new FTPConnection();
Cannot directly construct FTPConnection, use ftp_connect() or ftp_ssl_connect() instead

is_resource checks

User-land PHP code that work with ftp resources sometimes check for the validity of the resource object with is_resource function.

This was not necessary because ftp_connect and ftp_ssl_connect functions return false on error. This pattern is maintained in PHP 8.1 too.

To check if creation of an FTP resource was successful, a simple check for false is cross-version compatible, and is just as accurate as a is_resource check.

Existing code that relied on is_resource function now needs to account for the new FTPConnection class objects in PHP 8.1.

- is_resource($ftp_connection)
+ is_resource($ftp_connection) || $ftp_connection instanceof \FTPConnection

Alternately, a check against false might be more appropriate and more readable.

- is_resource($ftp_connection)
+ $ftp_connection !== false

Destroying FTPConnection objects

Destroying an FTPConnection object, or leaving it for the garbage collector to clean up will automatically close the FTP connection.

It is still possible to explicitly close the FTP connection with ftp_close function. This function is not deprecated and is still functional.

Attempting to use a closed FTP connection object will throw a ValueError exception.

ValueError: FTPConnection is already closed

Backwards Compatibility Impact

Similar to other resource to object migrations, FTP extension seamless upgrades return and accepted parameter types to the new object-based resources.

is_resource function now returns false instead of the previous true return value for FTP connection objects. This might be a backwards-compatibility issue if the FTP connection resources are checked with that function.


Implementation

IMAP: `imap` resources are `\IMAPConnection` class objects

TypeChange

In PHP 8.1, IMAP connection resources from the imap extension are migrated to class objects.

Prior to PHP 8.1, imap_open() function returned a resource object of type imap. From PHP 8.1 and later, it returns an \IMAPConnection class instance instead.

All functions that previously accepted resources accept the new type as well.

Resource to Object Migration
PHP is gradually phasing out all resource types with class objects, and this migration is one step of the Resource to Object Migration plan.

IMAPConnection Class Synopsis

final class IMAPConnection {}

In line with other resource to object migration semantics, the new IMAPConnection class is declared final as well, to minimize the potential backwards-compatibility breaks when PHP modifies the implementation details of the class.

imap_open function is still used to create IMAPConnection class instances, and instantiating with new IMAPConnection() construct is not allowed:

new IMAPConnection();
Cannot directly construct IMAPConnection, use imap_open() instead

is_resource checks

All resource to object migrated class objects no longer return true for is_resource function, and any code that used is_resource function to check the validity of an IMAP connection resource will cause problems in PHP 8.1 and later.

In all PHP versions, imap_open function returns false in case it failed to create an IMAP resource. This is still the case for PHP 8.1 and later as well.

Existing code that needs to check the validity of a given variable for an IMAP connection needs to account for IMAPConnection class object return values in PHP 8.1 and later.

- is_resource($imap_connection)
+ is_resource($imap_connection) || $imap_connection instanceof \IMAPConnection

Alternately, a check against false might be more appropriate and more readable, and works across all PHP versions too.

- is_resource($imap_connection)
+ $imap_connection !== false

Closing IMAPConnection resources

IMAP connections are automatically closed when the IMAPConnection is no longer referenced (i.e fall out of scope), or when explicitly destroyed with unset($connection).

imap_close function, that was used to close imap resources is still available and functional. Attempting to use a closed IMAPConnection object results in a \ValueError exception.

ValueError: IMAPConnection is already closed

Backwards Compatibility Impact

Following other resource to object migrations, IMAP extension seamless upgrades return and accepted parameter types to the new object-based resources.

is_resource function now returns false instead of the previous true return value for IMAP connection objects. This might be a backwards-compatibility issue if the IMAP connection resources are checked with that function. See is_resource checks section for possible workarounds


Implementation

finfo Extension: `file_info` resource are migrated to existing `finfo` objects

TypeChange

finfo extension has gone through the Resource to Object Migration, that the procedural API in the finfo extension transparently returns and accepts finfo class instances.


Resource to Object Migration
PHP is gradually phasing out all resource types with class objects, and this migration is one step of the Resource to Object Migration plan.


In PHP 8.1, the following functions from finfo extension return and accept finfo class instances instead of resource objects with type file_info.

finfo class

finfo class already exists in all PHP versions (PHP >= 5.3), but prior to PHP 8.1, the procedural-style finfo_* functions returned/accepted resources instead. From PHP 8.1, it is even possible to interchange the procedural return values with Object-Oriented style objects.

The finfo class continues to function with same semantics as before, and there are no changes in finfo class.

Destructing finfo class instances

The finfo_close function is still available, and is not deprecated.

Calling finfo_close no longer has any effect. It is possible to continue to use a closed resource, which was not possible prior to PHP 8.0.

$f = finfo_open();
finfo_close($f);
finfo_file($f, 'test.txt'); // Allowed in PHP 8.1, but not prior.

Prior to PHP 8.1, using a closed resource was not allowed, and the snippet above would have resulted in an error:

TypeError: finfo_file(): supplied resource is not a valid file_info resource

In PHP 8.1 and later, because the finfo_close function has no effect, this pattern does not result in an error.

finfo objects will be automatically destroyed when they fall out of scope. It is possible to destroy them explicitly as well:

unset($finfo);

Backwards Compatibility Impact

Similar to other Resource to Object Migration changes, the use of is_resource function on return value of finfo_open no longer returns true. It returns false instead.

To accept external finfo instances, it is now necessary to account for finfo class instances as well for compatibility with older PHP versions:

- is_resource($finfo)
+ is_resource($finfo) || $finfo instanceof finfo

Upon resource/object instantiation, a check against !== false is sufficient as well:

$finfo = finfo_open();
- is_resource($finfo);
+ $finfo !== false 

Alternately, a full-on migration to the OOP-style finfo class might be an easier upgrade, as it has no effective changes at all.

Apart from the is_resource function, the rest of the finfo API remains opaque, because all functions that previously accepted a file_info resource now accept finfo class objects.


Implementation

Pspell Extension: `pspell`, `pspell config` resources are `\PSpell`, `\PSpellConfig` class objects

TypeChange

All resource types from Pspell extension are migrated to opaque class objects in PHP 8.1.

Prior to PHP 8.1, Pspell extension used resource object types pspell and pspell config with an integer identifier. These two identifier values are replaced with class objects named PSpell and PSpellConfig.

All functions that previously returned and accepted resource integer identifiers now accept their corresponding class objects.

Resource to Object Migration
PHP is gradually phasing out all resource types with class objects, and this migration is one step of the Resource to Object Migration plan.

PSpell Class

PSpell class replaces the resource objects of type pspell. PHP returned an int identifier for this prior to PHP 8.1, and returns a PSpell class object in PHP 8.1 and later instead.

final class PSpell {}

All functions that returned or accepted pspell object identifiers are changed to return/accept new PSpell class objects.

The following functions are used to instantiate PSpell objects. They previously returned pspell resource identifiers as integers.

The following functions accepted pspell resource object identifiers, and are changed to accept PSpell class objects instead:

Instantiating a PSpell object with new PSpell construct is not allowed:

new PSpell();
PHP Error:  You cannot initialize a PSpell object except through helper functions in ... code on line ...

It is not allowed to serialize a PSpell object either:

serialize(pspell_new("en", "", "", ""));
Serialization of 'PSpell' is not allowed

PSpellConfig Class

The new PSpellConfig class replaces pspell config resource object identifiers (int values).

final class PSpellConfig {}

Similar to all other resource to class object migrations, all functions that returned/accepted pspell config resource object identifiers now accept PSpellConfig class instances.

  • pspell_config_create() function previously returned and int identifier for pspell config resource objects, but return PSpellConfig class instances instead in PHP 8.1 and later.

  • pspell_new_config() function previously accepted pspell config resource objects identifiers as int, and are changed to accept PSpellConfig class objects from PHP 8.1 and later.

It is not allowed to use new PSpellConfig construct to instantiate a PSpellConfig instance.

new PSpellConfig();
PHP Error:  You cannot initialize a PSpellConfig object except through helper functions in ... code on line ...

Further, it is not allowed to serialize a PSpell object either.

serialize(pspell_config_create('en'));
Serialization of 'PSpellConfig' is not allowed

Destroying PSpell resources

Prior to PHP 8.1, there were no specific functions to forcefully close a pspell/pspell config resource. PHP automatically cleans them with garbage cleaning.

From PHP 8.1 and later, the returned PSpell/PSpellConfig objects follow general object garbage-cleaning mechanisms, and they will be cleared when the objects fall out of scope. It is possible to explicitly destroy an object with unset() construct too.

Backwards Compatibility Impact

Prior to PHP 8.1, all pspell_* functions returned/accepted resource objects as integer identifiers. They are now changed in PHP 8.1 and later to return class objects instead.

Failure to instantiate any object return false, and this pattern is not changed in PHP 8.1.

It was possible to serialize the return values from pspell_* functions, erroneously so, prior to PHP 8.1, but the new class objects are not allowed to be serialized.


Implementation

`version_compare` operator restrictions

TypeChange

In PHP 8.1, the version_compare() function is made more strict with the operator parameter.

In PHP 8.0, this was made to throw a ValueError exception if an unknown parameter was passed, as part of the internal function exception handling changes.

In PHP 8.1, this is further restricted to disallow partial values for operator parameter.

version_compare(1, 2, '');
version_compare(1, 2, '!');
version_compare(1, 2, 'g');
version_compare(1, 2, 'l');
version_compare(1, 2, 'n');

All of the statements above are were allowed in PHP 8.0, and are no longer allowed in PHP 8.1. These values are undocumented values from the documentation.

Note that PHP 8.0 started to throw TypeError for all invalid values. The operators disallowed in PHP 8.1 are due to internal partial matching changes.

In PHP 8.1, only the following operators are allowed:

  • ==, =, and eq
  • !=, <>, and ne
  • > and gt
  • >= and ge
  • < and lt
  • <= and le

Backwards Compatibility Impact

PHP 8.0 started to disallow a vast majority of disallowed values, and this change in PHP 8.1 is a continuation of it. The disallowed values were not documented.

Using the correct values fixes the issue for all PHP versions.


Implementation