PHP RFC: Deprecate functions with overloaded signatures
- Date: 2023-01-31
- Author: Máté Kocsis kocsismate@php.net
- Target version: PHP 8.3
- Status: Implemented
- Implementation: https://github.com/php/php-src/pull/11703
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()
andarray_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.
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.
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.
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.
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.
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()
.
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()
.
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.
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.
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()
.
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.
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.
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.
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.
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.
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.
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 {}