rfc:mixed_type_v2
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:mixed_type_v2 [2020/03/22 23:41] – forked kocsismate | rfc:mixed_type_v2 [2020/04/28 14:44] – added note about explicit returns danack | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Mixed typehint | + | ====== PHP RFC: Mixed Type v2 ====== |
- | * Version: 0.1 | + | * Version: 0.9 |
* Date: 2020-03-23 | * Date: 2020-03-23 | ||
- | * Author: | + | * Author: |
- | * Target Version: 8.0 | + | * Based on previous RFC by: Michael Moravec |
- | * Status: | + | * Status: |
- | * Implementation: | + | * Implementation: |
- | * First Published at: http:// | + | * First Published at: https:// |
===== Introduction ===== | ===== Introduction ===== | ||
- | With the addition of scalar types in PHP 7, nullables in 7.1 and '' | + | With the addition of scalar types in PHP 7, nullables in 7.1, object in 7.2, and lastly, union types in 8.0, people writing PHP code can explicitly declare |
+ | |||
+ | However, PHP has not always supported types, | ||
+ | |||
+ | * the type is a specific type, but the programmer forgot to declare it. | ||
+ | * the type is a specific type, but the programmer omitted it to keep compatibility with an older PHP version | ||
+ | * the type is not currently expressible in PHP's type system, and so no type could be specified. | ||
+ | * for return types, it is not clear if the function will or will not return a value, other than null. | ||
+ | |||
+ | An explicit | ||
+ | |||
+ | Currently, '' | ||
+ | |||
+ | One prominent example where the '' | ||
+ | |||
+ | Additionally, | ||
+ | |||
+ | <code php> | ||
+ | var_dump ( mixed $expression [, mixed $... ] ) : void | ||
+ | </ | ||
===== Proposal ===== | ===== Proposal ===== | ||
- | This RFC proposes to add the '' | ||
- | ===== Motivation ===== | + | This RFC proposes to add the mixed type to be used in PHP's type system. A type of '' |
- | When no native type is present, it is unclear what type is expected - it could mean one of the following: | + | ==== LSP, Covariance |
- | - the value is mixed, and since '' | + | |
- | - the value is of specific type, but native type is omitted due to compatibility with older PHP version; | + | |
- | - the value is of specific type, but the native type was forgotten. | + | |
- | At the time of writing it is not possible | + | The proposal conforms |
- | Additionally, | + | Since 7.4 PHP allows [[https:// |
- | ===== Mixed and Void ===== | + | PHP allows contravariance (aka type widening) for parameter types to obey the LSP principle. A subclass may use a ' |
- | As of PHP 7.1, PHP has a special '' | + | PHP allows covariance (aka type narrowing) for return types to obey the LSP principle. A subclass may use a 'narrower' |
- | The difference between '' | + | ==== Parameter types are contravariant ==== |
- | - Mixed means **any** value is returned. | + | |
- | - Void means **no** value is returned. | + | |
- | Due to this difference, | + | A parameter type may be widened in a subclass from a specific value type to the '' |
- | ===== Type system hierarchy ===== | + | <code php> |
+ | // Valid example | ||
- | < | + | class A |
- | * | + | { |
- | | | + | |
- | | + | } |
- | | + | |
- | < | + | class B extends A |
- | | | + | { |
- | |-------------------------------------------------------------------| | + | // Parameter type was widened from int to mixed, this is allowed |
- | | | | + | |
- | < | + | } |
</ | </ | ||
- | ===== Nullability ===== | + | A parameter type may not be narrowed in a subclass to a more specific type as this is not contravariant and so violates LSP. |
- | As the '' | + | <code php> |
+ | // Invalid example | ||
+ | |||
+ | class A | ||
+ | { | ||
+ | public function foo(mixed $value) {} | ||
+ | } | ||
+ | |||
+ | class B extends A | ||
+ | { | ||
+ | | ||
+ | | ||
+ | public function foo(int $value) {} | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==== Return types are covariant ==== | ||
+ | |||
+ | The '' | ||
<code php> | <code php> | ||
- | function foo(?mixed $arg) {} // Fatal error: Mixed types cannot be nullable, null is already part of the mixed type. | + | // Valid example |
- | function bar() : ?mixed {} // Fatal error: Mixed types cannot be nullable, null is already part of the mixed type. | + | class A |
+ | { | ||
+ | public | ||
+ | } | ||
+ | |||
+ | class B extends A | ||
+ | { | ||
+ | | ||
+ | public function bar(): int {} | ||
+ | } | ||
</ | </ | ||
- | ===== Mixed vs. Void vs. no return type ===== | + | Specific |
- | 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 '' | + | <code php> |
+ | // Invalid example | ||
- | ====== Inheritance ====== | + | class C |
+ | { | ||
+ | public function bar(): int {} | ||
+ | } | ||
- | ======= Parameters ======= | + | class D extends C |
+ | { | ||
+ | // return type cannot be widened from int to mixed | ||
+ | // Fatal error thrown | ||
+ | public function bar(): mixed {} | ||
+ | } | ||
+ | </ | ||
- | As parameters cannot be '' | + | ==== Property types are invariant ==== |
+ | |||
+ | Following the [[typed properties RFC|https:// | ||
- | The following code is valid: | ||
<code php> | <code php> | ||
+ | // Invalid example | ||
+ | |||
class A | class A | ||
{ | { | ||
- | public | + | public |
- | | + | public int $bar; |
+ | | ||
} | } | ||
class B extends A | class B extends A | ||
{ | { | ||
- | | + | // property |
- | | + | |
+ | public int $foo; | ||
} | } | ||
- | class C extends | + | class C extends |
+ | { | ||
+ | // property type cannot be widened from int to mixed | ||
+ | // Fatal error thrown | ||
+ | public mixed $bar; | ||
+ | } | ||
+ | |||
+ | class D extends A | ||
+ | { | ||
+ | // property type cannot be added | ||
+ | // Fatal error thrown | ||
+ | public mixed $baz; | ||
+ | } | ||
+ | |||
+ | class E extends A | ||
{ | { | ||
- | | + | // property |
- | | + | |
+ | public $foo; | ||
} | } | ||
</ | </ | ||
- | ======= Return types ======= | + | ==== Void return type ==== |
- | Since return | + | The signature checking done in PHP for functions that return void does not currently allow covariance, even though that could be conformant |
<code php> | <code php> | ||
class A | class A | ||
{ | { | ||
- | public function | + | public function |
- | | + | |
} | } | ||
class B extends A | class B extends A | ||
{ | { | ||
- | public function | + | public function |
- | {} | + | } |
+ | |||
+ | // Fatal error: Declaration of B::bar(): int must be compatible with A::bar(): void | ||
+ | </ | ||
+ | |||
+ | The position of this RFC is to follow the existing behaviour: i.e. you can't widen the type from '' | ||
+ | |||
+ | ==== Signature checking of function when no parameter type present ==== | ||
+ | |||
+ | When no type is present for a function parameter, the signature checks for inheritance are done as if the parameter had a '' | ||
+ | |||
+ | <code php> | ||
+ | class A | ||
+ | { | ||
+ | // no type is specified, | ||
+ | public | ||
+ | } | ||
+ | |||
+ | class B extends A | ||
+ | { | ||
+ | | ||
+ | // type in parent class | ||
+ | public function foo(mixed $value) | ||
} | } | ||
class C extends B | class C extends B | ||
{ | { | ||
- | | + | // no type is specified, mixed type is assumed which is |
- | {} | + | // invariant to type in parent class |
+ | | ||
} | } | ||
class D extends B | class D extends B | ||
{ | { | ||
- | public function foo() : void // void type is specified, as void is not subtype of mixed, Fatal error is thrown | + | public function foo(mixed |
- | | + | |
} | } | ||
</ | </ | ||
- | ===== Variance ===== | + | Currently this only affects inheritance in classes. |
- | '' | + | If/when PHP gains the abilties to declare [[https:// |
- | - Parameter | + | |
- | - Specific return | + | ==== Signature checking of function when no return |
+ | |||
+ | When no type is present for a function return, | ||
+ | |||
+ | When no type is specified, the same method | ||
<code php> | <code php> | ||
class A | class A | ||
{ | { | ||
- | | + | |
- | {} | + | public function |
- | | + | |
- | public function | + | |
- | | + | |
} | } | ||
class B extends A | class B extends A | ||
{ | { | ||
- | public function foo(mixed $value) // parameter | + | |
- | | + | // covariant to ' |
- | + | // for this function. | |
- | public function | + | |
- | {} | + | } |
+ | |||
+ | class C extends B | ||
+ | { | ||
+ | | ||
+ | | ||
+ | | ||
+ | public function | ||
+ | } | ||
+ | |||
+ | class D extends B | ||
+ | { | ||
+ | | ||
+ | | ||
} | } | ||
</ | </ | ||
- | ===== Backward Incompatible Changes ===== | + | ==== The mixed|void union type ==== |
- | None, '' | + | The position of this RFC is that supporting a union of '' |
+ | |||
+ | ==== Nullability ==== | ||
+ | |||
+ | The '' | ||
+ | |||
+ | The position of this RFC is to not support nullability of '' | ||
+ | |||
+ | <code php> | ||
+ | //INVALID - Fatal error: Mixed types cannot be nullable, null is already | ||
+ | function foo(?mixed $arg) {} | ||
+ | |||
+ | //INVALID - Fatal error: Mixed types cannot be nullable, null is already part of the mixed type. | ||
+ | function bar(): ?mixed {} | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ==== Explicit returns ==== | ||
+ | |||
+ | When using mixed as a return type, a value must be explicitly returned from the function, otherwise a TypeError will be thrown. | ||
+ | |||
+ | <code php> | ||
+ | function foo(): mixed {} | ||
+ | |||
+ | foo(); | ||
+ | |||
+ | // Uncaught TypeError: Return value of foo() must be of | ||
+ | // the type mixed, none returned | ||
+ | </ | ||
+ | |||
+ | This is consistent with the existing behaviour for other return types. | ||
+ | |||
+ | <code php> | ||
+ | function bar(): ?int {} | ||
+ | bar(); | ||
+ | // Uncaught TypeError: Return value of bar() must be of | ||
+ | // the type int or null, none returned | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== Resource ' | ||
+ | |||
+ | Although variables can be a '' | ||
+ | |||
+ | The position of this RFC is that '' | ||
+ | |||
+ | ==== Mixed vs any ==== | ||
+ | |||
+ | This RFC proposes '' | ||
+ | |||
+ | Also, choosing to use '' | ||
+ | |||
+ | |||
+ | ====== RFC Impact ====== | ||
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | 7.4 | + | 8.0 |
+ | |||
+ | ===== Backward Incompatible Changes ===== | ||
+ | |||
+ | Since PHP 7.0, '' | ||
+ | |||
+ | ===== To SAPIs ===== | ||
+ | None known. | ||
+ | |||
+ | ===== To Existing Extensions ===== | ||
+ | None known. | ||
+ | |||
+ | ===== To Opcache ===== | ||
+ | Not analyzed. | ||
+ | |||
+ | ===== Proposed Voting Choices ===== | ||
- | ===== Proposed Voting Choices ===== | + | Add '' |
- | As this is a language change, 2/3 majority is required. | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | [[https:// | + | [[https:// |
===== References ===== | ===== References ===== |
rfc/mixed_type_v2.txt · Last modified: 2020/05/22 14:22 by kocsismate