rfc:deprecate_functions_with_overloaded_signatures

PHP RFC: Deprecate functions with overloaded signatures

Introduction

Method overloading may sound very familiar for Java developers, but PHP doesn't natively support this concept. In spite of this fact, due to historical reasons, many internal PHP functions and methods are implemented so that they can only be expressed with multiple signatures - making them overloaded after all.

In Java, being able to support multiple parameter types requires overloading function signatures, but it's not the case anymore with PHP since the introduction of union types. However, the predominant type of overloading is caused by functions accepting a varying number of parameters. Usually, these functions don't have clear default value handling semantics. But what does this mean in practice? A function has clear default value handling semantics if it has well-defined parameter default values, meaning that it behaves the same way when:

  • no optional parameters are explicitly passed to it (so their default values are implicitly used)
  • any of their optional parameters is explicitly passed its default value
function foo($bar = null) {
    ...
}
 
foo();
foo(null);
 
// The two foo() invocations must behave the same way

Besides, PHP has a few unconventionally overloaded methods whose behavior depend on whether they are accessed statically or as an instance method.

From year to year, PHP has less and less inconsistencies between internal and userland code, so in order to continue the effort, we should either add native support for signature overloading, or phase out the overloaded internal function signatures. As the former solution is widely known to be impossible to implement in an effective way, the latter solution is the preferred choice of this RFC. Maintaining consistency is not the only motivation why we should get rid of this long standing issue though.

Before PHP 8.0, overloaded signatures didn't cause a big harm, except for making the usability of the functions in question worse as well as their behavior more surprising due to the fact that these functions usually don't have meaningful parameter names and clear default value handling semantics. However, as of PHP 8.0, these have become ever more important due to the following reasons:

  • Since PHP 8.0, ReflectionParameter supports retrieving the default parameter values of internal functions, but only when the default value exists
  • In case of some overloaded functions, some parameters cannot be named properly, since they do completely different things in case of the different signatures (see session_set_save_handler() for example). Even though this imposes some problems for the documentation, it's mainly an issue when using Named Arguments, because a parameter can only have a single name, so it's not possible to convey their true meaning by referring to them by their name.
  • Furthermore, Named Arguments supports skipping optional parameters (as in implicitly passing their default value), but only when the default value exists.
  • For ~2 years now, the online manual at php.net is semi-automatically updated based on the exact signatures known by php-src, which are collected via the so-called stubs. Unfortunately, overloaded functions cannot be updated with our tooling, possibly leaving these signatures outdated, displaying the wrong parameter names and types, as well as missing proper default values.

After the named arguments RFC was accepted, dozens (if not hundreds) of functions were fixed in PHP 8.0 so that they started to behave according to clear default parameter value handling semantics. Usually, this required us to make the parameters nullable, but sometimes it was enough to make a few small adjustments to the parameter parsing code. As all the easier cases are fixed for quite a long time, this RFC tries to tackle the ones with some BC impact.

Proposal

This RFC consists of multiple votes to phase out the below mentioned overloaded function signatures over the course of either the 8.x or the 9.x version series, depending on the outcome of each vote. In order to reduce the BC impact and ease gradual migration, PHP 8.3 would only add the suggested replacements first if one is needed, then the next minor version (referred to as PHP 8.4 for simplicity) would actually deprecate the affected signatures. Finally, either the subsequent major PHP version (referred to as PHP 9.0 for simplicity) or the next after the next one (referred to as PHP 10.0 for simplicity) would completely remove support for them. If a suggested replacement for a signature is already available, then PHP 8.3 would deprecate it directly. In some cases (mostly, when a signature is rare), only PHP 9.0 is proposed as the target version of the scheduled removal.

Most votes about phasing out an overloaded signature have three choices:

  • Short path: a signature becomes deprecated in PHP 8.4 (or in PHP 8.3 when there is no need for introducing an alternative), and it will be removed preferably in PHP 9.0, or in 10.0 at last.
  • Long path: a signature becomes deprecated in PHP 8.4 (or in PHP 8.3 when there is no need for introducing an alternative), and it will be removed in PHP 10.0.
  • No: the signature should be neither deprecated, nor removed.

A few votes only include the “Short path” and “No” options. Please refer to the the first paragraph in the section for more details.

When will a signature be deprecated?

When the “Short path” combined with the “Long path” get 2/3 majority against the “No” votes. Otherwise, the signatures in question won't be deprecated.

When will a signature be removed?

  • in PHP 9.0: when the “Short path” gets 2/3 majority against the other options
  • in PHP 10.0: when the “Short path” combined with the “Long path” get 2/3 majority against the “No” votes

Otherwise the signatures in question won't be removed. Please refer to https://externals.io/message/120146#120238 for the reasoning behind the voting system and for an example scenario.

array_keys()

array_keys() currently supports two signatures: the former one returns all keys of $array, while the latter one returns the keys for those items where the value matches the $filter_value criteria.

function array_keys(array $array): array {}
 
function array_keys(array $array, mixed $filter_value, bool $strict = false): array {}

This RFC proposes to add a new function as a replacement for the 2nd signature in PHP 8.3, and deprecate calling array_keys() with 2 or more arguments in PHP 8.4. Finally, the deprecated signature would become unsupported either in PHP 9.0 or 10.0, resulting in the following functions:

function array_keys(array $array): array {}
 
function array_keys_filter(array $array, mixed $filter_value, bool $strict = false): array {}

Suggested backward compatible alternative for PHP <8.3: code which calls array_keys() with 2 or more arguments should either:

  • declare array_keys_filter() via a polyfill, and use the new function from that point forward
  • use the combination of array_filter() and array_keys() to retain the original behavior:
array_keys(
    array_filter(
        $array,
        function ($value, $key) {
            return $value == ARRAY_VALUE_TO_BE_FILTERED;
        },
        ARRAY_FILTER_USE_BOTH
    )
);

Impact analysis: Impact analysis was not performed due to implementation difficulties and the perceived low overall effect of the deprecation: even though the 1 parameter version of array_keys() is one of the most widespread functions, the deprecation only affects its 2+ parameter signature which is way less known and used.

Phase out the above mentioned signature of array_keys()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bukka (bukka)   
bwoebi (bwoebi)   
colinodell (colinodell)   
crell (crell)   
derick (derick)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
nikic (nikic)   
ocramius (ocramius)   
petk (petk)   
pollita (pollita)   
ramsey (ramsey)   
rasmus (rasmus)   
sergey (sergey)   
stas (stas)   
svpernova09 (svpernova09)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 13 1 15
This poll has been closed.

DatePeriod::__construct()

DatePeriod::__construct() currently supports three signatures, all of which instantiate the DatePeriod class in a slightly different way.

class DatePeriod
{
    ...
 
    public function __construct(DateTimeInterface $start, DateInterval $interval, int $recurrences, int $options = 0) {}
 
    public function __construct(DateTimeInterface $start, DateInterval $interval, DateTimeInterface $end, int $options = 0) {}
 
    public function __construct(string $isostr, int $options = 0) {}
 
    ...
}

This RFC proposes to add a new factory method as a replacement for the 3rd signature in PHP 8.3 and deprecate calling the constructor with 1 or 2 arguments in PHP 8.4. Finally, the deprecated signature would become unsupported either in PHP 9.0 or 10.0, resulting in the following methods:

class DatePeriod
{
    ...
 
    public function __construct(DateTimeInterface $start, DateInterval $interval, DateTimeInterface|int $end, int $options = 0) {}
 
    public static function createFromISO8601String(string $specification, int $options = 0): static {}
 
    ...
}

Suggested backward compatible alternative for PHP <8.3: code which calls DatePeriod::__construct() with 1 or 2 arguments should be modified to conditionally use the appropriate method based on the PHP version. Using a wrapper class is preferable when possible.

Impact analysis: None of the 2000 most popular PHP packages rely on instantiating DatePeriod with 1 or 2 arguments.

Phase out the above mentioned signature of DatePeriod::__construct()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bwoebi (bwoebi)   
colinodell (colinodell)   
crell (crell)   
derick (derick)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 23 0 0
This poll has been closed.

dba_fetch()

dba_fetch() serves for fetching data from Berkeley DB style databases, and currently supports two signatures:

function dba_fetch(string|array $key, resource $dba, int $skip = 0): string|false {}
 
function dba_fetch(string|array $key, int $skip, resource $dba): string|false {}

Oddly, the $dba and $skip parameters flip depending on the number of arguments passed.

This RFC proposes to deprecate the latter signature in PHP 8.3, and then calling dba_fetch() with the $dba parameter at the 3rd position would become unsupported in PHP 9.0, resulting in the following function:

function dba_fetch(string|array $key, resource $dba, int $skip = 0): string|false {}

Suggested backward compatible alternative for <PHP 8.2: code which invokes dba_fetch() with 3 arguments should be modified to conditionally use the appropriate signature based on the PHP version. Using a wrapper function is preferable when possible. Please note that PHP 8.2 already supports the preferred signature.

Impact analysis: None of the 2000 most popular PHP packages rely on calling dba_fetch() with 3 arguments.

Phase out the above mentioned signature of dba_fetch()?
Real name Yes, deprecate in 8.3, remove in 9.0 No
alcaeus (alcaeus)  
alec (alec)  
ashnazg (ashnazg)  
bwoebi (bwoebi)  
colinodell (colinodell)  
crell (crell)  
derick (derick)  
dharman (dharman)  
ericmann (ericmann)  
galvao (galvao)  
girgias (girgias)  
heiglandreas (heiglandreas)  
imsop (imsop)  
kalle (kalle)  
kocsismate (kocsismate)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
nikic (nikic)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sergey (sergey)  
theodorejb (theodorejb)  
trowski (trowski)  
Final result: 24 0
This poll has been closed.

FFI::cast(), FFI::new(), and FFI::type()

FFI::cast(), FFI::new(), and FFI::type() currently support two signatures each: the static ones operate on predefined types (e.g. int), while their instance method signatures also support cdef types (e.g.: $x = FFI::cdef(...); $x->new();).

class FFI
{
    ...
 
    public static function cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData {}
 
    public function cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData {}
 
    public static function new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData {}
 
    public function new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData {}
 
    public static function type(string $type): ?FFI\CType {}
 
    public function type(string $type): ?FFI\CType {}
 
    ...
}

Since invoking FFI::cast(), FFI::new(), and FFI::type() as instance methods is more universally usable, this RFC proposes to deprecate their static counterparts in PHP 8.3. Calling these methods statically would become unsupported either in PHP 9.0 or 10.0, resulting in the following methods:

class FFI
{
    ...
 
    public function cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData {}
 
    public function new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData {}
 
    public function type(string $type): ?FFI\CType {}
 
    ...
}

Suggested backward compatible alternative: code which invokes the affected methods statically should be modified to call them as instance methods.

Impact analysis: 1 out of the 2000 most popular PHP packages relies on calling any of FFI::cast(), FFI::new(), and FFI::type() statically.

Phase out the above mentioned signatures of FFI::cast(), FFI::new(), and FFI::type()?
Real name Yes, deprecate in 8.3, remove in 9.0 or 10.0 Yes, deprecate in 8.3, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bwoebi (bwoebi)   
crell (crell)   
ericmann (ericmann)   
galvao (galvao)   
heiglandreas (heiglandreas)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
nikic (nikic)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 19 0 0
This poll has been closed.

get_class() and get_parent_class()

get_class() currently supports two signatures: the first one retrieves the class name of the provided object, while the latter retrieves the class name of the current class context.

function get_class(object $object): string {}
 
function get_class(): string {}

These are due to the get_class() disallow null parameter RFC which was implemented in PHP 7.2. As it can be seen from the RFC, the parameter of get_class doesn't have a well-defined default value anymore.

Additionally, the get_parent_class() function behaves the same way:

function get_parent_class(object|string $object_or_class): string {}
 
function get_parent_class(): string {}

This RFC proposes to deprecate the signatures without parameters in PHP 8.3, and then calling get_class() as well as get_parent_class() without parameters would become unsupported either in PHP 9.0 or 10.0, resulting in the following functions:

function get_class(object $object): string {}
 
function get_parent_class(object|string $object_or_string): string {}

Suggested backward compatible alternative: code which invokes get_class() without parameters should be modified to use self::class or get_class($this) instead, while code which invokes get_parent_class() without parameters should be modified to use parent::class or ReflectionClass::getParentClass() instead.

Impact analysis: 10 out of the 2000 most popular PHP packages rely on calling get_class() with 0 arguments, while none of the projects rely on calling get_parent_class() with 0 arguments.

Phase out the above mentioned signature of get_class()?
Real name Yes, deprecate in 8.3, remove in 9.0 or 10.0 Yes, deprecate in 8.3, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bwoebi (bwoebi)   
colinodell (colinodell)   
crell (crell)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 22 0 0
This poll has been closed.

IntlCalendar::set()

IntlCalendar::set() currently supports the following signatures: the first one modifies a given field, while the latter ones modify several of them at once.

class IntlCalendar
{
    ...
 
    public function set(int $field, int $value): true {}
 
    public function set(int $year, int $month, int $dayOfMonth): true {}
 
    public function set(int $year, int $month, int $dayOfMonth, int $hour, int $minute): true {}
 
    public function set(int $year, int $month, int $dayOfMonth, int $hour, int $minute, int $second): true {}
 
    ...
}

It's important to note that it's not possible call IntlCalendar::set() with 4 arguments, as the ICU library which is triggered under the hood neither supports it.

This RFC proposes to add two new methods as a replacement for the latter three signatures in PHP 8.3 and deprecate calling the set() method with 3 or more arguments in PHP 8.4. Finally, the deprecated signatures would become unsupported either in PHP 9.0 or 10.0, resulting in the following methods:

class IntlCalendar
{
    ...
 
    public function set(int $field, int $value): true {}
 
    public function setDate(int $year, int $month, int $dayOfMonth): void {}
 
    public function setDateTime(int $year, int $month, int $dayOfMonth, int $hour, int $minute, ?int $second = null): void {}
 
    ...
}

Please note that the newly added methods have a void return type. This is possible because IntlCalendar::set() always returns true.

As IntlCalendar::set() is an alias of intlcal_set(), the deprecation and then the removal would apply to the function as well. Since the procedural-style API of the intl extension is considered legacy, this RFC proposes to deprecate intlcal_set() as of PHP 8.4, and remove it either in PHP 9.0 or 10.0.

Suggested backward compatible alternative for PHP <8.3: code which calls IntlCalendar::set() with 3 or more arguments should be modified to either:

  • set the different fields one by one, as this is what the underlying library does under the hood
  • conditionally invoke the appropriate signature based on the PHP version. Using a wrapper class is preferable when possible.

Impact analysis: None of the 2000 most popular PHP packages rely on calling IntlCalendar::set() or intlcal_set().

Phase out the above mentioned signatures of IntlCalendar::set() and intlcal_set()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bukka (bukka)   
bwoebi (bwoebi)   
crell (crell)   
derick (derick)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 16 3 4
This poll has been closed.

IntlGregorianCalendar::__construct()

IntlGregorianCalendar::__construct() currently supports three signatures, all of which instantiate the IntlGregorianCalendar class based on different data.

class IntlGregorianCalendar
{
    ...
 
    public function __construct(IntlTimeZone|DateTimeZone|string|null $timezone = null, ?string $locale = null) {}
 
    public function __construct(int $year, int $month, int $dayOfMonth) {}
 
    public function __construct(int $year, int $month, int $dayOfMonth, int $hour, int $minute, ?int second = null) {}
 
    ...
}

It's important to note that it's not possible call IntlGregorianCalendar::__construct() with 4 arguments, as the ICU library which is triggered under the hood neither supports it.

This RFC proposes to add two new static methods as a replacement for the latter two signatures in PHP 8.3 and deprecate calling the constructor with more than two arguments in PHP 8.4. Finally, the deprecated signatures would become unsupported either in PHP 9.0 or 10.0, resulting in the following methods:

class IntlGregorianCalendar
{
    ...
 
    public function __construct(IntlTimeZone|DateTimeZone|string|null $timezone = null, ?string $locale = null) {}
 
    public static function createFromDate(int $year, int $month, int $dayOfMonth): static {}
 
    public static function createFromDateTime(int $year, int $month, int $dayOfMonth, int $hour, int $minute, ?int second = null): static {}
 
    ...
}

As IntlGregorianCalendar::__construct() shares the same implementation with intlgregcal_create_instance(), they have the same issues. Since the procedural-style API of the intl extension is considered legacy, this RFC proposes to deprecate intlgregcal_create_instance() as of PHP 8.4, and remove it either in PHP 9.0 or 10.0.

Suggested backward compatible alternative for PHP <8.3: code which calls IntlGregorianCalendar::__construct() with 3 or more arguments should be modified to conditionally invoke the appropriate signature based on the PHP version. Using a wrapper class is preferable when possible.

Impact analysis: None of the 2000 most popular PHP packages rely on calling IntlGregorianCalendar::__construct() or intlgregcal_create_instance().

Phase out the above mentioned signatures of IntlGregorianCalendar::__construct() and intlgregcal_create_instance()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bukka (bukka)   
bwoebi (bwoebi)   
crell (crell)   
derick (derick)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 16 3 4
This poll has been closed.

ldap_connect()

ldap_connect() currently supports two signatures depending on the platform: by default, the first one is available, except when PHP is compiled with OracleLDAP.

function ldap_connect(?string $uri = null, int $port = 389): LDAP\Connection|false {}
 
function ldap_connect(
    ?string $uri,
    int $port,
    string $wallet,
    string $password,
    int $auth_mode
): LDAP\Connection|false {}

This RFC proposes to add a new function as a replacement for the 2nd signature (when PHP is compiled with OracleLDAP) in PHP 8.3, and deprecate calling ldap_connect() with 3 or more arguments in PHP 8.4. Finally, the deprecated signature would become unsupported in PHP 9.0, resulting in the following functions:

function ldap_connect(?string $uri = null, int $port = 389): LDAP\Connection|false {}
 
function ldap_connect_wallet(?string $uri, string $wallet, string $password, int $auth_mode): LDAP\Connection|false {}

The new function doesn't have the $port parameter because it's currently being deprecated by Deprecations for PHP 8.3.

Suggested backward compatible alternative for PHP <8.3: code which calls ldap_connect() with 3 or more arguments should declare ldap_connect_wallet() via a polyfill, and use the new function from that point forward.

Impact analysis: None of the 2000 most popular PHP packages rely on calling ldap_connect() with 3 or more arguments.

Phase out the above mentioned signature of ldap_connect()?
Real name Yes, deprecate in 8.4, remove in 9.0 No
alcaeus (alcaeus)  
alec (alec)  
ashnazg (ashnazg)  
bwoebi (bwoebi)  
crell (crell)  
derick (derick)  
dharman (dharman)  
ericmann (ericmann)  
galvao (galvao)  
girgias (girgias)  
heiglandreas (heiglandreas)  
kalle (kalle)  
kocsismate (kocsismate)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sergey (sergey)  
theodorejb (theodorejb)  
trowski (trowski)  
Final result: 21 0
This poll has been closed.

ldap_exop()

ldap_exop() currently supports two signatures: the former one performs an extended LDAP operation asynchronously, while the latter one performs it synchronously depending on whether the $response_data parameter is provided.

function ldap_exop(
    LDAP\Connection $ldap,
    string $request_oid,
    ?string $request_data = null,
    ?array $controls = null
): LDAP\Result|false {}
 
/**
 * @param string $response_data
 * @param string $response_oid
 */
function ldap_exop(
    LDAP\Connection $ldap,
    string $request_oid,
    ?string $request_data = null,
    ?array $controls = null,
    &$response_data,
    &$response_oid
): bool {}

This RFC proposes to add a new function as a replacement for the 2nd signature, and deprecate calling ldap_exop() with 5 or more arguments in PHP 8.4. Finally, the deprecated signature would become unsupported in PHP 9.0, resulting in the following functions:

function ldap_exop(
    LDAP\Connection $ldap,
    string $request_oid,
    ?string $request_data = null,
    ?array $controls = null
): LDAP\Result|false {}
 
/**
 * @param string $response_data
 * @param string $response_oid
 */
function ldap_exop_sync(
    LDAP\Connection $ldap,
    string $request_oid,
    ?string $request_data = null,
    ?array $controls = null,
    &$response_data = null,
    &$response_oid = null
): bool {}

Suggested backward compatible alternative for PHP <8.3: code which calls ldap_exop() with 5 or more arguments should either declare ldap_exop_sync() via a polyfill, and use the new function from that point forward, or the async API should be used instead.

Impact analysis: 1 out of the 2000 most popular PHP packages rely on calling ldap_exop() with 5 or more arguments.

Phase out the above mentioned signature of ldap_exop()?
Real name Yes, deprecate in 8.4, remove in 9.0 No
alcaeus (alcaeus)  
alec (alec)  
ashnazg (ashnazg)  
bwoebi (bwoebi)  
crell (crell)  
ericmann (ericmann)  
galvao (galvao)  
girgias (girgias)  
heiglandreas (heiglandreas)  
kalle (kalle)  
kocsismate (kocsismate)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sergey (sergey)  
theodorejb (theodorejb)  
trowski (trowski)  
Final result: 19 0
This poll has been closed.

pg_fetch_result(), pg_field_prtlen(), and pg_field_is_null()

pg_fetch_result(), pg_field_prtlen(), and pg_field_is_null() currently support two signatures each:

function pg_fetch_result(PgSql\Result $result, mixed $field): string|false|null {}
 
function pg_fetch_result(PgSql\Result $result, int $row, mixed $field): string|false|null {}
function pg_field_prtlen(PgSql\Result $result, string|int $field): int|false {}
 
function pg_field_prtlen(PgSql\Result $result, int $row, string|int $field): int|false {}
function pg_field_is_null(PgSql\Result $result, string|int $field): int|false {}
 
function pg_field_is_null(PgSql\Result $result, int $row, string|int $field): int|false {}

This RFC proposes to make the $row parameters nullable in PHP 8.3, and deprecate the 2 parameter signatures (which don't have $row) in PHP 8.4. Finally, calling pg_fetch_result(), pg_field_prtlen(), and pg_field_is_null() without passing either the $row or the 3rd parameter would become unsupported either in PHP 9.0 or 10.0, resulting in the following functions:

function pg_fetch_result(PgSql\Result $result, ?int $row, mixed $field): string|false|null {}
 
function pg_field_prtlen(PgSql\Result $result, ?int $row, string|int $field): int|false {}
 
function pg_field_is_null(PgSql\Result $result, ?int $row, string|int $field): int|false {}

Since all these functions have an alias (pg_result(), pg_fieldprtlen(), and pg_fieldisnull respectively), the deprecations would affect them as well. However, as these aliases have already been deprecated, there is no use to change them in any way. That's why this RFC proposes not to implement the above mentioned changes in case of the aliases in question.

Suggested backward compatible alternative for PHP <8.3: code which calls the affected functions without providing the $row parameter should be modified to conditionally invoke the appropriate signature based on the PHP version. Using a wrapper function is preferable when possible.

Impact analysis: 1 out of the 2000 most popular PHP packages relies on calling pg_field_prtlen() and pg_field_is_null() with 2 arguments. None of the 2000 most popular PHP packages relies on calling pg_fetch_result().

Phase out the above mentioned signatures of pg_fetch_result(), pg_field_prtlen(), and pg_field_is_null()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bwoebi (bwoebi)   
crell (crell)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 19 1 0
This poll has been closed.

Phar::setStub()

Phar::setStub() currently supports two signatures which create a stub file based on either a string or a resource.

class Phar
{
    ...
 
    public function setStub(string $string) {}
 
    public function setStub(resource $resource, int $length) {}
 
    ...
}

This RFC proposes to deprecate the latter signature in PHP 8.3 and then remove its support in PHP 9.0, resulting in the following method:

class Phar
{
    ...
 
    public function setStub(string $string) {}
 
    ...
}

Phar::setStub($resource, $length) reads the input resource into memory as a string and then continues evaluation just like if a string was passed. That's why this signature is trivial to replace with $phar->setStub(stream_get_contents($resource));

As the implementation of Phar::setStub() is “aliased” to PharData::setStub(), this RFC proposes to implement the above mentioned changes in case of PharData::setStub() as well.

Suggested backward compatible alternative: code which calls Phar::setStub() or PharData::setStub() with a resource argument should rather pass stream_get_contents($resource).

Impact analysis: None of the 2000 most popular PHP packages rely on calling Phar::setStub() or PharData::setStub() with a resource argument.

Phase out the above mentioned signature of Phar::setStub() and PharData::setStub()?
Real name Yes, deprecate in 8.3, remove in 9.0 No
alcaeus (alcaeus)  
alec (alec)  
ashnazg (ashnazg)  
crell (crell)  
derick (derick)  
ericmann (ericmann)  
galvao (galvao)  
girgias (girgias)  
heiglandreas (heiglandreas)  
imsop (imsop)  
kalle (kalle)  
kocsismate (kocsismate)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sergey (sergey)  
theodorejb (theodorejb)  
trowski (trowski)  
Final result: 20 0
This poll has been closed.

ReflectionMethod::__construct()

ReflectionMethod::__construct() currently supports two signatures: the former one instantiates the ReflectionMethod class based on an object/class name and a method name, while the latter one uses a string consisting of a class name and a method name separated by “::” (e.g.: Foo::bar).

class ReflectionMethod
{
    ...
 
    public function __construct(object|string $objectOrClass, string $method) {}
 
    public function __construct(string $classMethod) {}
 
    ...
}

This RFC proposes to add the following new factory method in PHP 8.3 and deprecate the second constructor signature in PHP 8.4. Finally, the deprecated signature would become unsupported in either PHP 9.0 or 10.0, resulting in the following methods:

class ReflectionMethod
{
    ...
 
    public function __construct(object|string $objectOrClass, string $method) {}
 
    public static function createFromMethodName(string $method): static {}
 
    ...
}

Suggested backward compatible alternative for PHP <8.3: code which calls ReflectionMethod::__construct() with a single string argument should explode the string into an array ($rm = new ReflectionMethod(...explode(“::”, $string));).

Impact analysis: 10 out of the 2000 most popular PHP packages rely on calling ReflectionMethod::__construct() with 1 argument.

Phase out the above mentioned signature of ReflectionMethod::__construct()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
ashnazg (ashnazg)   
bwoebi (bwoebi)   
crell (crell)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 18 1 0
This poll has been closed.

ReflectionProperty::setValue()

ReflectionProperty::setValue() currently supports three signatures:

class ReflectionProperty
{
    ...
 
    public function setValue(object $object, mixed $value): void {}
 
    public function setValue(mixed $unused, mixed $value): void {}
 
    public function setValue(mixed $value): void {}
 
    ...
}

The latter two signatures are exclusive to static properties for which an object instance is unnecessary to operate on. The $unused parameter is actually completely disregarded when the property is static.

This RFC proposes to make the $object parameter nullable in PHP 8.3, and deprecate the latter two signatures of ReflectionProperty::setValue(). Finally, the deprecated signatures would become unsupported in PHP 9.0, resulting in the following method:

class ReflectionProperty
{
    ...
 
    public function setValue(?object $object, mixed $value): void {}
 
    ...
}

The $object parameter must be object for instance properties. Conversely, it can be either null or object for static properties.

Suggested backward compatible alternative: code which invokes ReflectionProperty::setValue() for a static property with a single argument should be modified to pass null as the first parameter, code which invokes ReflectionProperty::setValue() for a static property with an incorrect first argument (which is neither object, nor null) should pass null instead.

Impact analysis: Impact analysis was not performed due to implementation difficulties and the perceived low overall effect of the deprecation: it only affects static properties where the setValue() method either passed one argument, or the first argument is incorrect (which should be very rare). Also, the suggested backward compatible alternative is available at least since PHP 5.2, so the “fix” is trivially backward compatible.

Phase out the above mentioned signatures of ReflectionProperty::setValue()?
Real name Yes, deprecate in 8.3, remove in 9.0 No
alcaeus (alcaeus)  
alec (alec)  
ashnazg (ashnazg)  
bwoebi (bwoebi)  
crell (crell)  
derick (derick)  
ericmann (ericmann)  
galvao (galvao)  
girgias (girgias)  
heiglandreas (heiglandreas)  
imsop (imsop)  
kalle (kalle)  
kocsismate (kocsismate)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sergey (sergey)  
theodorejb (theodorejb)  
trowski (trowski)  
Final result: 16 5
This poll has been closed.

session_set_save_handler()

session_set_save_handler() currently supports two signatures:

function session_set_save_handler(SessionHandlerInterface $session_handler, bool $register_shutdown = true): bool {}
 
function session_set_save_handler(
    callable $open,
    callable $close,
    callable $read,
    callable $write,
    callable $destroy,
    callable $gc,
    ?callable $create_sid = null,
    ?callable $validate_sid = null,
    ?callable $update_timestamp = null): bool {}

This RFC proposes to deprecate calling session_set_save_handler() with 6 or more arguments in PHP 8.4. Finally, the deprecated signature would become unsupported either in PHP 9.0 or 10.0, resulting in the following signature:

function session_set_save_handler(SessionHandlerInterface $session_handler, bool $register_shutdown = true): bool {}

Suggested backward compatible alternative: code which calls session_set_save_handler() with 6 or more arguments should wrap the callbacks into a SessionHandlerInterface implementation.

Impact analysis: 1 out of the 2000 most popular PHP packages rely on calling session_set_save_handler() with 6 or more arguments.

Phase out the above mentioned signature of session_set_save_handler()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
ashnazg (ashnazg)   
bwoebi (bwoebi)   
colinodell (colinodell)   
crell (crell)   
derick (derick)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 17 4 1
This poll has been closed.

stream_context_set_option()

stream_context_set_option() currently supports two signatures: the former one sets a single config option for a stream wrapper, while the latter one sets an array of stream context options.

/** @param resource $context */
function stream_context_set_option(
    $context,
    string $wrapper,
    string $option_name,
    mixed $value
): true {}
 
/** @param resource $context */
function stream_context_set_option($context, array $options): bool {}

This RFC proposes to add a new function as a replacement for the 2nd signature in PHP 8.3, and deprecate calling stream_context_set_option() with 2 arguments in PHP 8.4. Finally, the deprecated signature would become unsupported either in PHP 9.0 or 10.0, resulting in the following functions:

function stream_context_set_option(
    $context,
    string $wrapper,
    string $option_name,
    mixed $value
): true {}
 
/** @param resource $context */
function stream_context_set_options($context, array $options): bool {}

Suggested backward compatible alternative for PHP <8.3: code which calls stream_context_set_option() with 2 arguments should either:

  • declare stream_context_set_options() via a polyfill, and use the new function from that point forward
  • use the already available stream_context_set_parameters() function instead with a slightly modified $params argument which has the following shape: array{notification?: mixed, options?: array}

Impact analysis: 10 out of the 2000 most popular PHP packages rely on calling stream_context_set_option() with 2 arguments.

Phase out the above mentioned signature of stream_context_set_option()?
Real name Yes, deprecate in 8.4, remove in 9.0 or 10.0 Yes, deprecate in 8.4, remove in 10.0 No
alcaeus (alcaeus)   
alec (alec)   
ashnazg (ashnazg)   
bukka (bukka)   
bwoebi (bwoebi)   
colinodell (colinodell)   
crell (crell)   
derick (derick)   
dharman (dharman)   
ericmann (ericmann)   
galvao (galvao)   
girgias (girgias)   
heiglandreas (heiglandreas)   
imsop (imsop)   
kalle (kalle)   
kocsismate (kocsismate)   
mauricio (mauricio)   
nicolasgrekas (nicolasgrekas)   
ocramius (ocramius)   
petk (petk)   
ramsey (ramsey)   
sergey (sergey)   
theodorejb (theodorejb)   
trowski (trowski)   
Final result: 18 5 1
This poll has been closed.

Policy about new functions

Newly added internal functions and methods must not have overloaded signatures. Existing, not overloaded ones cannot be modified to become overloaded.

Forbid the declaration of new overloaded signatures?
Real name Yes No
alcaeus (alcaeus)  
alec (alec)  
ashnazg (ashnazg)  
bukka (bukka)  
bwoebi (bwoebi)  
colinodell (colinodell)  
crell (crell)  
derick (derick)  
dharman (dharman)  
ericmann (ericmann)  
galvao (galvao)  
girgias (girgias)  
heiglandreas (heiglandreas)  
kalle (kalle)  
kocsismate (kocsismate)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
nikic (nikic)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sergey (sergey)  
theodorejb (theodorejb)  
trowski (trowski)  
Final result: 24 0
This poll has been closed.

Backwards incompatible changes

Additional deprecation notices will start to appear in PHP 8.3 and 8.4. In PHP 9.0 and/or PHP 10.0, the previously deprecated functionality will be removed.

Impact on extensions

None.

Future scope

Unfortunately, the removal of a few overloaded functions and methods is not covered by this or any other RFCs. These should be tackled later in order to completely get rid of overloaded signatures.

The list of overloaded functions and methods with ill-defined default values (denoted by UNKNOWN) not yet deprecated by any RFCs:

function array_walk(array|object &$array, callable $callback, mixed $arg = UNKNOWN): true {}
 
function array_walk_recursive(array|object &$array, callable $callback, mixed $arg = UNKNOWN): true {}
 
function mt_rand(int $min = UNKNOWN, int $max = UNKNOWN): int {}
 
function rand(int $min = UNKNOWN, int $max = UNKNOWN): int {}
 
class SoapHeader
{
    public function __construct(
        string $namespace,
        string $name,
        mixed $data = UNKNOWN,
        bool $mustUnderstand = false,
        string|int|null $actor = null
    ) {}
}
 
function stream_filter_append($stream, string $filter_name, int $mode = 0, mixed $params = UNKNOWN) {}
 
function stream_filter_prepend($stream, string $filter_name, int $mode = 0, mixed $params = UNKNOWN) {}
 
class ReflectionClass implements Reflector {
    public function getStaticPropertyValue(string $name, mixed $default = UNKNOWN): mixed {}
}

In most cases, these functions have a parameter with the mixed type which gets passed to something else (i.e.: array_walk passes $arg to the $callback callable). The problem with these parameters is two-fold:

  • As an optimization, we generally want to avoid passing these values to their target when no meaningful value is provided.
  • They accept any values due to the mixed type, so there is no way to signal unmeaningful values

The list of overloaded functions and methods with well-defined default parameter values which are not yet deprecated by any RFCs:

/* Parameter #1 is overloaded */
function session_set_cookie_params(
    array|int $lifetime_or_options,
    ?string $path = null,
    ?string $domain = null,
    ?bool $secure = null,
    ?bool $httponly = null
): bool {}
 
/* Parameter #3 is overloaded */
function setcookie(
    string $name,
    string $value = "",
    array|int $expires_or_options = 0,
    string $path = "",
    string $domain = "",
    bool $secure = false,
    bool $httponly = false
): bool {}
 
/* Parameter #3 is overloaded */
function setrawcookie(
    string $name,
    string $value = ?,
    array|int $expires_or_options = 0,
    string $path = ?,
    string $domain = ?,
    bool $secure = false,
    bool $httponly = false
): bool {}
rfc/deprecate_functions_with_overloaded_signatures.txt · Last modified: 2023/08/20 12:09 by kocsismate