THIS DOCUMENT HAS BEEN RETIRED. SEE THE FULL RFC: https://wiki.php.net/rfc/never_for_parameter_types
Arguments in PHP are contravariant to preserve Liskov substitution. This means that if class B extends class A, then redefines a function call, the entire type of that argument from class A must be present in the type of the argument in class B:
<?php
abstract class A {
abstract public function foo(int $arg);
}
class B extends A {
public function foo(int|float $arg) {
return round($arg) + 1;
}
}
Thus, the more specific a type is for an argument in a base class, the more broad it can be in an extending class with the requirement that it must also include the type from the base class.
Since never
is a bottom type within the PHP engine, all other types contain it. This RFC proposes allowing never
as a valid argument type for methods on interfaces and abstract functions.
With the never
type available, interfaces and abstracts would be able to require that implementing classes provide a type without specifying any details about what that type must be. This would allow use cases such as the following:
<?php
interface CollectionInterface {
public function add(never $input): self;
}
Implementers of the CollectionInterface
could then specify any type they want, but failing to specify a type would result in a Fatal Error. Functions which use collections could then type against the interface, allowing any of the variously typed implementations to be provided.
In this way, allowing the never
type for interfaces and abstracts could be a method of providing minimal support for generics while avoiding the challenges that providing generics represents. It would also not prevent or make it more difficult to provide full generics in the future.
Providing internal interfaces that require a type but do not specify which type can be very beneficial. In fact, the motivation for exploring this concept originated in researching operator overloads and the interfaces that such a feature would provide.
While it could be argued that the meaning of never
was that code using this type would terminate, a new type offers several issues over using never
:
never
already represents the concept of a bottom type in PHP due to its usage with return types. The engine already has the concept of this type built in, but is not currently exposing it for use with arguments. Having multiple bottom types not only doesn't make sense, but I cannot find a single instance of any programming language having multiple bottom types.never
correctly indicates that the code which uses it for an argument type can never be called directly.- This usage has precedence in other languages; see below.
There are several languages which contain a bottom type, some of which use never
as their bottom type. The behavior described in this RFC is in fact how never
behaves and can be used in TypeScript, which also uses never
as its bottom type.
Scala also uses the bottom type to denote covariant parameter polymorphism, though the bottom type in Scala is Nothing
.
Allow the use of never
as a type for arguments in interfaces and classes. This would have the following semantics:
never
cannot be used in an intersection type or union type. Any intersection would reduce tonever
, and any union would reducenever
out of the union, asnever
is the identity type of unions.- Attempting to call code directly that uses the
never
type for an argument would result in aTypeError
, as no zval will match this type.
This means that an interface or class could allow implementers and subclasses to declare a type for an argument without restricting that type to anything particular.
None
This change is proposed for PHP 8.2
None
None
None
None
None
Allow never
as a parameter type: yes/no. A 2/3 vote is required to pass.