PHP 8.0: New mixed pseudo type

Version8.0
TypeNew Feature

mixed is a pseudo type added in PHP 8 that conveys the type of the parameter/return/property can be of any type. mixed type includes all scalar types in PHP, null, all class objects, callable, and even resource.

mixed is equivalent to a Union Type of:

string|int|float|bool|null|array|object|callable|resource

With mixed, it is now possible to declare mixed as the type when the parameters, returns, and class properties can be of any type.

class Example {
    public mixed $exampleProperty;
    public function foo(mixed $foo): mixed {}
}

mixed is a pseudo type

mixed represents any type PHP can handle, and thus you cannot cast a variable to mixed because it simply doesn't make sense.

$foo = (mixed) $bar;

Further, there is no is_mixed() function for the same reasons.

gettype()and get_debug_type() functions will never return mixed as the type of a variable either.

mixed in union with other types

Because mixed represents all types, mixed cannot be used in union with other types:

function (mixed|FooClass $bar): int|mixed {}

Both union types above are not allowed, and will result in a fatal error:

Fatal error: Type mixed can only be used as a standalone type in ... on line ...

mixed is assumed when no type is declared

When a function parameter or a class property has no explicit type declared, the type is now assumed to be mixed.

Be mindful when you add mixed type to all your existing code; PHP 8 has Union Types that might be a better fit because Union Types allow you to be more specific.

For return types, lack of an explicit return type is equal to mixed|void.

However, note that you cannot declare mixed|void as a return type because mixed is not allowed in a Union Type.

Type variance

When a class method, return type, or a property type is overridden by a sub-class, Liskov Substitution Principle is respected.

Contravariance: mixed parameters types

Function parameter types can be "widened" at a child class or an interface implementation because the widened type still fulfills the contract of the interface/parent class. This means child class parameters can declare a type with a Union Type that includes more types, or a class name that is a parent of the current class.

When a parameter type is declared as mixed, this practically prevents further contravariance because mixed includes all types PHP works with. If possible, always opt for more specific types because once you mark a parameter type as mixed in a public API, all child classes must be capable to deal with mixed types.

Covariance: mixed return types

If a parent class method has declared a return type other than mixed, child classes will not be allowed to declare mixed because it widens the return type scope, thus breaking LSP.

class A {
    public function foo(): mixed {}
}
class B extends A{
    public function foo(): void {}
}

The above will result in a fatal error:

Fatal error: Declaration of B::foo(): void must be compatible with A::foo(): mixed

This is because mixed does not include void type. If a return type is not explicitly declared, it is assumed to be mixed|void.

All following declarations are allowed:

class A {
    public function foo() {}
    public function bar() {}
    public function baz(): mixed {}
}
class B extends A{
    public function foo(): mixed {}
    public function bar(): void {}
    public function baz(): string {}
}
  • B::foo: Allowed: Narrows down the assumed mixed|void return type of A::foo.
  • B::bar: Allowed: Narrows down the assumed mixed|void return type of A::bar.
  • B::baz: Allowed: Narrows down the declared mixed type.

Invariance: mixed property types

If a property type is declared as mixed, this type cannot be omitted or changed at all.

Usage with void

PHP supports void pseudo return type to indicate that the function will not return anything. This is equivalent to lack of a return statement, or return; expression without setting an explicit value.

void type and mixed cannot be in a union. Further mixed does not include void.

Nullable mixed types

It is not allowed to declare mixed type as nullable because mixed includes null.

All of the following declarations are not allowed:

function foo(mixed|null $foo) {}
function foo(?mixed $foo) {}
function foo($foo): mixed|null {}
function foo($foo): ?mixed {}

All declarations above will raise a fatal error:

Fatal error: Type mixed can only be used as a standalone type in ... on line ...

Practical Usage

Many PHP internal functions accept various types, which can now be declared with the mixed type. However, for user-land functions, it is often better to use a specific type or a Union Type.

Functions such var_dump or get_debug_type() can declare its parameters as mixed because these functions accept any type by definition.

If you declare a parameter/return type/class property as mixed type, be mindful that mixed includes types such resource and callable, which are not easily stored, serialized, sanitized, or displayed.

Most user-land functions that need to "accept anything", such as logging functions are better off with a Union Type such as string|int|float|bool|null|object|array.


Backwards compatibility

mixed is soft-reserved since PHP 7. Until PHP 8, it is technically possible to declare a class with name mixed, and it will not raise any errors, warnings, or notices. PHPDoc standard widely used mixed as a type declaration, so it is highly unlikely that even the wildest code base out there declares a class with name mixed.

Attempting to declare a class with name mixed in PHP 8 results the following error:

Fatal error: Cannot use 'mixed' as class name as it is reserved in ... on line ...

Polyfill

It is not possible to polyfill this functionality because it's an internal type. If you use mixed type anywhere in your code, be sure that it will always run on a PHP 8+ platform.


Related Changes


RFC Discussion Implementation