This RFC would like to discuss options for reserving primitive type names int
, integer
, float
, double
, bool
, boolean
and string
.
Reserving the names as suggested e.g. by the 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.
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:
This first option suggests reserving primitive type names.
use
This second option suggests allowing primitive type names in combination with namespaces, but disallowing them in global scope.
use
The following would work:
namespace types; class Int { ... } // ... another file: function sum(\types\Int $a, \types\Int $b): \types\Int { ... }
This would allow primitive type names in combination with namespaces, and accept imports, overriding primitive definitions.
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.
This option would add special handling to the primitive types names and allow all situations in which a different casing was used.
Or, in code:
class int { } // Parse error: Cannot use primitive type name "int" class Int { } // OK
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.
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.
PHP 7.0
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):
lib/Cake/Utility/String.php
src/Joomla/Filesystem/Stream/String.php
library/Zend/XmlRpc/Value/String.php
core/lib/Drupal/Component/Utility/String.php
src/main/php/lang/types/String.class.php
This code search for a PHP String class suggests various more libraries will be affected. Same goes for “Boolean”, “Integer”, “Int”, “Float” and “Double”
Extend these rules to resource
and the pseudo-type mixed
, as well as possibly even array
and callable
.
Voting on options to give the discussion a direction.
(TODO)
(TODO)
(TODO)