====== PHP RFC: Reserving primitive types ======
* Version: 0.9
* Date: 2015-02-08
* Author: Timm Friebe, thekid@php.net
* Status: Draft
* First Published at: https://wiki.php.net/rfc/reserve_primitives
This RFC would like to discuss options for reserving primitive type names ''int'', ''integer'', ''float'', ''double'', ''bool'', ''boolean'' and ''string''.
===== Introduction =====
Reserving the names as suggested e.g. by the [[https://wiki.php.net/rfc/scalar_type_hints|scalar types hints RFC]] will create problems if people have used them as class, interface or trait names. Creating BC problems slows adoption, so they should be outweighed with benefits.
===== Proposal =====
The motivation for reserving the names stems from a possible ambiguity allowing them would create.
class int { ... }
function sum(int $a, int $b): int { ... }
In this case, it's not clear what the ''int'' in the method signature stands for: PHP's native primitive or the userland class?
Using the above is a bit unfair towards the real-life situation: The majority of frameworks in PHP nowaday uses a) namespaces and b) would capitalize the type name, giving us:
namespace types;
class Int { ... }
// ... another file:
function sum(\types\Int $a, \types\Int $b): \types\Int { ... }
// ... yet another file:
use types\Int;
function sum(Int $a, Int $b): Int { ... }
Purely looking from a reader's perspective, the first example is surely not to be confused with anything that is a primitive. For the second example, it's a bit harder to judge, though to me personally, it would still be OK.
The options this RFC suggests discussing are:
==== Option 1: Reserve ====
This first option suggests reserving primitive type names.
* BC break: No global class, interface or trait can be named after a primitive type name.
* BC break: No namespaced class, interface or trait can be named after a primitive type name.
* BC break: No class, interface or trait named after a primitive name can be imported with ''use''
==== Option 2: Allow namespaced ====
This second option suggests allowing primitive type names in combination with namespaces, but disallowing them in global scope.
* BC break: No global class, interface or trait can be named after a primitive type name
* BC break: No class, interface or trait named after a primitive name can be imported with ''use''
The following would work:
namespace types;
class Int { ... }
// ... another file:
function sum(\types\Int $a, \types\Int $b): \types\Int { ... }
==== Option 3: Allow namespaces and use ====
This would allow primitive type names in combination with namespaces, and accept imports, overriding primitive definitions.
* BC break: No class, interface or trait in the global namespace can be named after a primitive type name
The following would work:
namespace types;
class Int { ... }
// ... another file:
use types\Int;
function sum(Int $a, Int $b): Int { ... }
To the reader, it's *probably* clear because of the uppercasing. If a lowercase class was used, this would be confusing. Looking at real-life frameworks and libraries, we'd usually find the first case.
==== Option 4: Case insensitivity exception ====
This option would add special handling to the primitive types names and allow all situations in which a different casing was used.
* BC break: No class, interface or trait in the global namespace can be named *exactly* after a primitive type name
Or, in code:
class int { } // Parse error: Cannot use primitive type name "int"
class Int { } // OK
==== Option 5: Use cast-tokens ====
This would make any situation unambigous, reuse already existing parser tokens, and create no BC breaks:
// The primitive
function sum((int) $a, (int) $b): (int) { ... }
// Always the int class
function sum(\types\Int $a, \types\Int $b): \types\Int { ... }
function sum(Int $a, Int $b): Int { ... }
function sum(int $a, int $b): int { ... }
Fair enough, this is counter-intuitive to the syntax used so far for arrays and callables as well as for value types; and the majority of other programming languages.
==== Option 6: Do not reserve ====
The type names would not be reserved. No BC breaks occur, while it's also not possible to use them for parameter and return type hints. For both situations, alternative suggestions, e.g. along a "design by contract" RFC are discussed.
===== Proposed PHP Version(s) =====
PHP 7.0
===== RFC Impact =====
In all situations except the last two options, reserving primitive type names causes a BC break. The options above sketch out how we can cope with this, balancing the usefulness of being able to use these tokens and backwards compatibility on the other side.
These frameworks would be affected by reserving the word "string" (incomplete list):
* CakePHP - ''lib/Cake/Utility/String.php''
* Joomla - ''src/Joomla/Filesystem/Stream/String.php''
* ZF2 - ''library/Zend/XmlRpc/Value/String.php''
* Drupal8 - ''core/lib/Drupal/Component/Utility/String.php''
* XP Framework - ''src/main/php/lang/types/String.class.php''
This [[https://searchcode.com/?q=class+String&lan=24|code search for a PHP String class]] suggests various more libraries will be affected. Same goes for "Boolean", "Integer", "Int", "Float" and "Double"
===== Future Scope =====
Extend these rules to ''resource'' and the pseudo-type ''mixed'', as well as possibly even ''array'' and ''callable''.
===== Proposed Voting Choices =====
Voting on options to give the discussion a direction.
===== Patches and Tests =====
(TODO)
===== Implementation =====
(TODO)
===== References =====
* https://wiki.php.net/rfc/scalar_type_hints
* https://wiki.php.net/rfc/scalar_type_hints_v_0_1#open_issues (Discussion about reserving names)
===== Rejected Features =====
(TODO)