With the addition of scalar types in PHP 7, nullables in 7.1 and object
in 7.2, it's now possible to explicitly declare accepted types for most of the parameters and return types. Unfortunately without mixed
type it's still not possible to achieve a fully type hinted and consistent code using simple types.
This RFC proposes to add the mixed
type to be used for parameter and return types when the function or method returns any value.
When no native type is present, it is unclear what type is expected - it could mean one of the following:
mixed
type does not exist, no native type was specified;At the time of writing it is not possible to differentiate between the abovementioned scenarios.
Additionally, as values of mixed type cannot be typehinted upon, it is not possible to achieve full native type coverage.
As of PHP 7.1, PHP has a special void
type - it is not a value type and is only valid for return types to specify that nothing is returned.
The difference between mixed
and void
is as follows:
Due to this difference, void
is not a subtype of mixed
.
* | |---------------------------|---------------------------| | | <mixed> <void> | |-------------------------------------------------------------------| | | | | | | | | | <string> <bool> <int> <float> <resource> <array> <object> <callable> <null>
As the mixed
is a union type that accepts any value type, including null, nullable mixed type (?mixed
) is forbidden at compile time. This behaviour also conforms to the current usage in documentation.
function foo(?mixed $arg) {} // Fatal error: Mixed types cannot be nullable, null is already part of the mixed type. function bar() : ?mixed {} // Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
When a function does not have a native return type, it means it either returns some value or does not return any value. More formally, this would be expressed as mixed|void
. This behaviour is fully backward compatible.
As parameters cannot be void
, when no native type is present, it is equivalent to mixed
type and are interchangeable.
The following code is valid:
class A { public function foo($value) // no type is specified, mixed type is assumed {} } class B extends A { public function foo(mixed $value) // mixed type is explicitly specified, conforming to parent declaration {} } class C extends B { public function foo($value) // no type is specified, mixed type is assumed and conforms to parent declaration {} }
Since return types may be either mixed
or void
, the behaviour is slightly more complicated compared to parameters. When no type is specified, subclass must either also declare no type, declare void
or declare mixed
(or any other value type which is subtype of mixed
). Additionally neither mixed
nor void
return types could be changed back to no type since this would widen the resulting type.
class A { public function foo() // no type is specified, mixed|void is assumed {} } class B extends A { public function foo() : mixed // mixed type is explicitly specified, function must return some value {} } class C extends B { public function foo() // no type is specified, mixed|void is assumed which is incompatible with mixed type only - Fatal error is thrown {} } class D extends B { public function foo() : void // void type is specified, as void is not subtype of mixed, Fatal error is thrown {} }
Mixed
type fully supports variance.
mixed
type.mixed
type.class A { public function foo(int $value) {} public function bar() : mixed {} } class B extends A { public function foo(mixed $value) // parameter type was widened from int to mixed, this is allowed {} public function bar() : int // return type was narrowed from mixed to int, this is allowed {} }
None, mixed
is already a reserved word since PHP 7.0.
7.4
None.
None.
Not analyzed, likely none (no changes to current language behaviour).
No changes to type cast operators.
Simple yes/no vote to either accept or reject addition of mixed type. As this is a language change, 2/3 majority is required.