This is an old revision of the document!
PHP RFC: Allow void override
- Version: 1.0
- Date: 2019-02-04
- Author: Wes (@WesNetmo)
- Status: Under Discussion
- First Published at: http://wiki.php.net/rfc/allow-void-variance
Introduction
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 RFC; it eliminates pointless restrictions.
Rationale
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.
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()
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, it is a pointless restriction to disallow void
to be changed to a type in child classes.
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.