This is an old revision of the document!
PHP RFC: Allow void return type variance
- Version: 1.0
- Date: 2019-02-04
- Author: Wes (@WesNetmo)
- Status: Under Discussion
- First Published at: http://wiki.php.net/rfc/allow-void-variance
Rationale
This RFC proposes to change void
's behavior in class methods, because the current behavior resulted to cause more annoyance than benefit. What is proposed is backward compatible and in accordance with the goals of the previous void
RFC.
The intent of void
should be simply making clear to the reader that the function does not return anything useful, and that any attempt to use the returned value should be considered an invalid operation.
It shouldn't do more than that, but currently it also denies methods to be overridden with different types in subclasses.
class Foo{ function method (): void {} } class Bar extends Foo{ function method (): array { return []; } // fails } class Baz extends Foo{ function method () { return 42; } // also fails }
This should be allowed because it is causing discontent among users, and, most importantly, because it achieves nothing at all apart getting in the way of the developers.
function myFooConsumer (Foo $foo) { // method() is void, therefore we won't be using its return type $foo->method(); }
If a Bar
object is passed to the function (i.e. myFooConsumer(new Bar())
), even if Bar::method()
now returns an array
,
it is not breaking the code in myFooConsumer
, because the function myFooConsumer
has no interest in the return value of
method()
at all.
Even if it's receiving a Bar
object, the function was originally written to be compatible with Foo
objects.
The method()
can return anything, or nothing at all, but myFooConsumer
just does not care about it.
For this reason adding a type to subclasses is not an invalid operation, and denying it is a pointless restriction.
Proposal
This RFC proposes to allow void
to be changed to any type or mixed
in sub classes.
The rest of the current behavior of void
is preserved.
A void
return's inheritance would work exactly like mixed
; that is, the following methods follow the very same covariance rules:
class Foo{ function method1 (): void {} function method2 () {} } class Bar extends Foo{ function method1 (): array { return []; } function method2 (): array { return []; } } class Baz extends Foo{ function method1 () { return 42; } function method2 () { return 42; } }
Except that method1
, unlike method2
, makes clear that it's not returning anything (but it might do so in subclasses).
void
can be overridden to any type including mixed
and void
itself, but mixed
can't be overridden with void
like so:
class Foo{ function method (): void {} } class Bar extends Foo{ function method () {} // ok } class Baz extends Bar{ function method (): void {} // error: can't go back to void }
This is not technically invalid since mixed
includes null
, but it certainly feels “not LSP-valid” and it's therefore disallowed by this RFC.
Backward Incompatible Changes
None.
Proposed PHP Versions
7.2.x, 7.3.x, 7.4.x
Voting
2/3 majority will be required.