====== PHP RFC: Class name type ====== * Version: 0.1 * Date: 2017-04-29 * Author: Andrea Faulds, ajf@ajf.me * Status: Draft * First Published at: http://wiki.php.net/rfc/class_and_interface_name_types ===== Introduction ===== There are various cases where the fully-qualified name of a class or interface may be returned from or passed as an argument to a function. While PHP has a type declaration for function names, callable, it does not yet have such a type declaration for class or interface names. ===== Proposal ===== This RFC proposes the introduction of a new type declaration for use on parameters and return values, the class type declaration. It would accept the fully-qualified name of a class or interface. It would validate its value using the following steps: - If the value is not a string, reject it. - If there is no currently-loaded class, interface, or trait with the name given by the value, attempt to autoload it. - If there is now no currently-loaded class or interface with the name given by the value, reject the value. - Otherwise, accept the value. As a parameter type, it would permit default values of NULL (to make the parameter null) and constant strings (including ::class syntax). A simple example of usage: ===== Rationale and Points for Discussion ===== ==== Naming: "class" vs "classname"? ==== This RFC currently proposes to call this type declaration class. Hack, PHP's sister language, already [[https://docs.hhvm.com/hack/types/type-system#type-aliases__classname|includes a similar type for class names]], but calls it ''classname'' instead. The name class has a few advantages: * It is short * It is already a reserved word, so introducing it requires no backwards-incompatibility break * It resembles the ::class syntax for obtaining the name of a class * It avoids the redundancy of saying "name", given PHP does not represent classes as values in any other way (excepting reflection) * It aligns with how PHP treats a class and its fully-qualified name the same in several places (e.g. new $class and $class::$property) However, there are also arguments in favour of ''classname'': * It conveys more directly that the value is a string containing a class name * It is already in use by Hack, so using this would prevent further divergence between Hack and PHP ==== Should "class" include only classes, or both classes and interfaces? ==== This RFC currently proposes that there would be a single new type, class, which would accept the names of both classes and interfaces. There might, however, be a case to be made for accepting only classes, and/or having a separate type for interface names (interface, say), or even a third type for accepting both classes and interfaces. Having class accept both classes and interfaces has a few arguments in its favour: * It limits the number of new types that are introduced (one versus two or three) * It aligns with the internal ''zend_parse_parameters()'' type ''"C"'', used by some functions in the PHP standard library, which likewise accepts both class and interface names * It aligns with how ::class works for both class and interface names * Interfaces are essentially glorified abstract classes * PHP internally represents interfaces as a kind of class * Reflection represents interfaces as a kind of class * The type declaration need not be perfectly fine-grained, as the function body can check if the value given is an interface itself That being said, there are also arguments in favour of class accepting only classes: * Class and interface definitions use different keywords * class_exists() treats interfaces as non-existent * It might be surprising to see the name of an //interface// be passed as an argument to a parameter typed "class" There is an advantage to a separate interface type, insofar as having PHP distinguish classes and interfaces in type declarations makes for clearer function signatures and avoids potential manual testing of whether a value is class or an interface. If there was a separate interface type, there would be an argument for having the class type also accept interfaces, since classes are a superset of interfaces, and classes can subclass (“implement”) interfaces, but not the other way around. If none of these approaches are palatable, there could be a //third// type accepting both classes and interfaces, perhaps named ''classlike''. However, this might be reaching the point of diminishing returns. All the possibilities in this section can and have been implemented provisionally, and the branch on GitHub contains all of them in its commit history. ===== Backward Incompatible Changes ===== The class keyword is already a reserved word, so there is no backwards-compatibility break created by its reuse here. ===== Proposed PHP Version(s) ===== This is proposed for the next PHP 7.x, currently PHP 7.2. ===== RFC Impact ===== ==== To Opcache ==== Testing revealed that Opcache's type inference needed updating to accommodate the new type declaration. This has been done and it seems to work, but it is possible other areas of incompatibility exist and have been missed. ===== Unaffected PHP Functionality ===== Classes, interfaces and traits continue not to be objects in themselves, and are only referenced by name. ===== Future Scope ===== A supertype could be introduced, which could name not only classes and interfaces, but also primitive PHP types (int, string etc.) and possibly pseudo-types. The potential future ability to use variables containing type names in place of literal type names in source code could facilitate generic programming. ===== Proposed Voting Choices ===== This would require a 2/3 majority, as a language change. The vote would be a Yes/No vote as to whether to accept the RFC for the appropriate future version of PHP. ===== Patches and Tests ===== There is a patch here which contains tests: https://github.com/php/php-src/compare/master...hikari-no-yume:class_type_declaration The commits for versions with multiple new types do not handle inheritance concerns. There is not yet a pull request. There is not yet a patch for the language specification. ===== Implementation ===== After the project is implemented, this section should contain - the version(s) it was merged to - a link to the git commit(s) - a link to the PHP manual entry for the feature - a link to the language specification section (if any) ===== References ===== FIXME: Links to external references, discussions or RFCs