# RFC: Mixed typehint

- Status: Obsolete
- Authors: Michael Moravec (php.net@majkl578.cz)
- Date: 2017-07-19
- Version: 1.2
- Original: https://wiki.php.net/rfc/mixed-typehint
- Page: https://externals.io/rfc/mixed-typehint
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Discussions on the mailing list

- [\[RFC\] Mixed Typehint](https://externals.io/message/101371.md) — started on 2017-12-19, 27 messages
- [\[RFC\] Mixed type](https://externals.io/message/102536.md) — started on 2018-06-30, 10 messages
- [Mixed type-hint](https://externals.io/message/104300.md) — started on 2019-02-08, 11 messages

---

## Introduction

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.

## Proposal

This RFC proposes to add the `mixed` type to be used for parameter and return types when the function or method returns any value.

## Motivation

When no native type is present, it is unclear what type is expected - it could mean one of the following:

1. the value is mixed, and since `mixed` type does not exist, no native type was specified;
2. the value is of specific type, but native type is omitted due to compatibility with older PHP version;
3. the value is of specific type, but the native type was forgotten.

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.

## Mixed and Void

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:

1. Mixed means **any** value is returned.
2. Void means **no** value is returned.

Due to this difference, `void` is not a subtype of `mixed`.

## Type system hierarchy

```
                                                                *
                                                                |
                                    |---------------------------|---------------------------|
                                    |                                                       |
                                 <mixed>                                                  <void>
                                    |
   |-------------------------------------------------------------------|
   |        |     |      |        |         |       |         |        |
<string> <bool> <int> <float> <resource> <array> <object> <callable> <null>
```

## Nullability

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.

```php
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.
```

## Mixed vs. Void vs. no return 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.

# Inheritance

# Parameters

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:

```php
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
    {}
}
```

# Return types

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.

```php
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
    {}
}
```

## Variance

`Mixed` type fully supports variance.

1. Parameter type may be widened in a subclass from a specific value type to the `mixed` type.
2. Specific return type could be narrowed in a subclass by using the `mixed` type.

```php
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
    {}
}
```

## Backward Incompatible Changes

None, `mixed` is already a reserved word since PHP 7.0.

## Proposed PHP Version(s)

7.4

## RFC Impact

### To SAPIs

None.

### To Existing Extensions

None.

### To Opcache

Not analyzed, likely none (no changes to current language behaviour).

## Unaffected PHP Functionality

No changes to type cast operators.

## Proposed Voting Choices

Simple yes/no vote to either accept or reject addition of mixed type. As this is a language change, 2/3 majority is required.

## Patches and Tests

[GitHub Pull request #2063](https://github.com/php/php-src/pull/2603)

## References

- [PHP RFC: Reserve Even More Types in PHP 7](https://externals.io/rfc/reserve_even_more_types_in_php_7)
- [phpDocumentor type reference](https://www.phpdoc.org/docs/latest/guides/types.html)
