PHP 8.0: Deprecate required parameters after optional parameters in function/method signatures

Version8.0
TypeDeprecation

When declaring a function or a method, adding a required parameter after optional parameters is deprecated since PHP 8.0.

This means the following function signature triggers a deprecation notice:

function foo($param_optional = null, $param_required) {
//           ^^ optional parameter , ^^ required parameter
}

From PHP 8.0 onwards:

Deprecated: Required parameter $param_required follows optional parameter $param_optional in ... on line ...

If you have a require parameter (i.e. a parameter without a default value set in its signature) after an optional one (i.e. a parameter with a default value), it makes all parameters before it essentially required because the caller has to explicitly pass a value for optional parameters as well.

To quote a bug submitted to bugs.php.net back in 2010:

PHP does not emit a notice of any kind when defining a function with a required
parameter after an optional parameter. For example:
function foo($optional = 1, $required) {}

It doesn't make sense to define a required parameter after an optional one,
since that effectively makes all preceding optional parameters required. Since this is
an error that can produce bugs and other warnings if one is not careful (calling
the above function with less than two parameters will cause warnings to be
emitted for the missing $required parameter), PHP should emit a warning of some kind
when functions like this are defined.

PHP documentation already explains that having required parameters after optional parameters is incorrect. There was no deprecation notice until PHP 8.0, even though it hints a likely issue in the code architecture.

Nullable parameters

If you have used typed parameters with a default value set to null, you can use nullable types instead. To provide an example:

function foo(string $param_optional = null, $param_required) {
//           ^^ poormans nullable param   , ^^ required parameter
}

This "trick" was used with PHP 7.0, there was no nullable type support until PHP 7.1. The snippet above can be replaced with the following:

function foo(?string $param_optional, $param_required) {
//           ^^ optional parameter  , ^^ required parameter
}

The deprecation does not apply if there is a type declared on the optional parameter, and the default value is null.

The following will not trigger a deprecation notice:

function foo(string $param_optional = null, $param_required) {}

This is because there is a type (string) declared for the optional $param_optional parameter, and its default value is null. Setting any other default value (such as $param_optional = 'bar'), or not declaring the type will trigger the deprecation notice.

Thanks to M1keSkydive and the_alias_of_andrea for the insight to extend this part.

Backwards compatibility impact

If you have any functions/methods that have required parameters after optional parameters, you will get a deprecation notice similar to the one in the example. It is most likely an indication of poorly defined architecture. The deprecation notice is triggered at the compile time, and it will be raised even if it is not called.

You can work around it by removing the default value in all optional parameters before the last required parameter. This should not break your existing code because all callers must pass a value to the optional parameters before proving values for the required parameters that appear later.


RFC Externals.io discussion Implementation