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:
neveralready 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.nevercorrectly 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:
nevercannot be used in an intersection type or union type. Any intersection would reduce tonever, and any union would reduceneverout of the union, asneveris the identity type of unions.- Attempting to call code directly that uses the
nevertype 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.