What's new in PHP 8.0 - behind the scenes

Built-in Stubs

All internal functions and methods (4149) have complete type info

PHP_FUNCTION(gettype)
{
	zval *arg;
	zend_string *type;

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_ZVAL(arg)
	ZEND_PARSE_PARAMETERS_END();

	type = zend_zval_get_legacy_type(arg);
	if (EXPECTED(type)) {
		RETURN_INTERNED_STR(type);
	} else {
		RETURN_STRING("unknown type");
	}
}

mixed

string

string

function gettype(mixed $value) {}

Built-in Stubs

  • PHP itself: "arginfo" structures are generated for reflection information

  • 3rd party tooling: e.g. static analysers

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gettype, 0, 1, IS_STRING, 0)
	ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()

Stubs are consumed by:

Fixing Parameter Validation

Internal function parameter validation (ZPP) used to be largely inconsistent

// Parameter count validation was forgotten:
get_defined_vars(null);
// Nothing happens

// The first parameter was always parsed weakly,
// regardless of strict_types mode
printf([]);
// array

// The second parameter was always parsed strictly,
// regardless of strict_types mode
chown("/temp/foo.txt", false);
// Warning: Parameter 2 should be string or int

// Parameter validation was omitted when the DOM
// extension is not enabled
(new XmlReader())->expand("wrong parameter");
// Warning: DOM support is not enabled

Fixing Parameter Validation

Now, only a few dozens of parameters with weird types don't behave in a standard way:

  • OpenSSLAsymmetricKey|OpenSSLCertificate|array|string
  • callable|bool
  • SoapHeader|array|null
  • IntlTimeZone|string|int|float|null
  • and a few more

Fixing Default Value Handling

450+ internal functions didn't have proper default value handling

var_dump(substr("abc", 0));
var_dump(substr("abc", 0, null));

var_dump(getenv("ENV_VAR"));
var_dump(getenv());
var_dump(getenv(null));

Fixing Default Value Handling

Now, there are only 63 functions left, mainly with overloaded signatures:

rand();        // works
rand(0, 100);  // works
rand(10);      // doesn't work

Reflection Info for Default Values

Reflection info for default values of internal functions was not available

class MyDateTimeZone extends DateTimeZone
{
    public static function listIdentifiers()
    {
    }
}

// PHP 7.4:

// Declaration of MyDateTimeZone::listIdentifiers() should be compatible with
// DateTimeZone::listIdentifiers($what = NULL, $country = NULL)

// PHP 8.0:

// Declaration of MyDateTimeZone::listIdentifiers() must be compatible with
// DateTimeZone::listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, 
// ?string $countryCode = null)

Consistent Parameter Names

<?php

function array_walk(array|object &$input, callable $funcname, mixed $userdata): bool {}
function array_walk(array|object &$input, callable $callback, mixed $argument): bool {}

class DomNode
{
    public function C14NFile(
        string $uri, bool $exclusive = false, bool $with_comments = false,
        ?array $xpath = null, ?array $ns_prefixes = null,
    ) {}
    public function C14NFile(
        string $uri, bool $exclusive = false, bool $withComments = false,
        ?array $xpath = null, ?array $nsPrefixes = null,
    ) {}
}

function openssl_x509_check_private_key(OpenSSLCertificate|string $x509, $key): bool {}
function openssl_x509_check_private_key(OpenSSLCertificate|string $certificate, $private_key): bool {}

All the parameter names are currently being reviewed

Error Promotions

count(null);

// PHP 7.4:
// count(): Parameter must be an array or an object that implements Countable

// PHP 8.0:
// count(): Argument #1 ($var) must be of type Countable|array, null given

version_compare("7.4.0", "8.0.0.", "?");

// PHP 7.4:
// null

// PHP 8.0:
// version_compare(): Argument #3 ($operator) must be a valid comparison operator

700+ warnings were reclassified as an exception

Resource to Object Conversion

  • cURL

  • OpenSSL

  • sockets

  • shmop

  • sysvmsg

  • sysvsem

  • sysvshm

  • XML-RPC

  • ZIP

  • ZLIB

Resource to Object Conversion

There are only 13 extensions which still define resources

  • fileinfo (fixed in PHP 8.1)

  • FTP (fixed in PHP 8.1)

  • com

  • DBA

  • GD

  • IMAP

  • LDAP

  • MySQLi

  • OCI8

  • ODBC

  • PDO

  • pgsql

  • pspell

  • SOAP

  • standard

Error Message Changes

Hundreds of error messages were improved

<?php

rand([], 1);
foo();

// PHP 7.4:
// rand() expects parameter 1 to be int, array given
// Argument 1 passed to foo() must be of the type int, array given

// PHP 8.0:
// rand(): Argument #1 ($min) must be of type int, array given
// foo(): Argument #1 ($i) must be of type int, array given

foreach(null as $i) {}

// PHP 7.4:
// Warning: Invalid argument supplied for foreach()

// PHP 8.0:
// Warning: foreach() argument must be of type array|object, null given

count([], 2);

// PHP 7.4:
// 0 is returned, the $mode parameter is ignored

// PHP 8.0:
// count(): Argument #2 ($mode) must be either COUNT_NORMAL or COUNT_RECURSIVE

What's new in PHP 8.0 - Behind the Scenes

By Máté Kocsis

What's new in PHP 8.0 - Behind the Scenes

  • 568