rfc:scalar_type_hints_v5

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
rfc:scalar_type_hints_v5 [2015/02/18 20:54] – fix typo ircmaxellrfc:scalar_type_hints_v5 [2017/09/22 13:28] – external edit 127.0.0.1
Line 1: Line 1:
 ====== PHP RFC: Scalar Type Declarations ====== ====== PHP RFC: Scalar Type Declarations ======
-  * Version: 0.5.0+  * Version: 0.5.3
   * Date: 2015-02-18   * Date: 2015-02-18
   * Author: Anthony Ferrara <ircmaxell@php.net> (original Andrea Faulds, ajf@ajf.me)   * Author: Anthony Ferrara <ircmaxell@php.net> (original Andrea Faulds, ajf@ajf.me)
-  * Status: Draft+  * Status: Implemented
   * First Published at: http://wiki.php.net/rfc/scalar_type_hints_v5   * First Published at: http://wiki.php.net/rfc/scalar_type_hints_v5
   * Forked From: http://wiki.php.net/rfc/scalar_type_hints   * Forked From: http://wiki.php.net/rfc/scalar_type_hints
Line 9: Line 9:
 ===== Summary ===== ===== Summary =====
  
-This RFC proposes the addition of four new type declarations for scalar types: ''int'', ''float'', ''string'' and ''bool''. These type declarations would behave identically to the existing mechanisms that built-in PHP functions use. It also proposes to add two new aliases: ''integer'' and ''boolean''.+This RFC proposes the addition of four new type declarations for scalar types: ''int'', ''float'', ''string'' and ''bool''. These type declarations would behave identically to the existing mechanisms that built-in PHP functions use. 
  
 This RFC further proposes the addition of a new optional per-file directive, ''declare(strict_types=1);'', which makes all function calls and return statements within a file have "strict" type-checking for scalar type declarations, including for extension and built-in PHP functions. In addition, calls to extension and built-in PHP functions with this directive produce an ''E_RECOVERABLE_ERROR'' on parameter parsing failure, bringing them into line with existing userland type declarations. This RFC further proposes the addition of a new optional per-file directive, ''declare(strict_types=1);'', which makes all function calls and return statements within a file have "strict" type-checking for scalar type declarations, including for extension and built-in PHP functions. In addition, calls to extension and built-in PHP functions with this directive produce an ''E_RECOVERABLE_ERROR'' on parameter parsing failure, bringing them into line with existing userland type declarations.
Line 20: Line 20:
   * ''declare(strict_types=1) {}'' (block mode) is specifically disallowed.   * ''declare(strict_types=1) {}'' (block mode) is specifically disallowed.
   * ''int'' types can resolve a parameter type of ''float''. So calling ''requiresAFloat(10)'' will work. Note that there is no overflow or precision check (see Discussion section for more).   * ''int'' types can resolve a parameter type of ''float''. So calling ''requiresAFloat(10)'' will work. Note that there is no overflow or precision check (see Discussion section for more).
 +  * aliases are removed (''integer'' and ''boolean'')
  
 ===== Details ===== ===== Details =====
Line 25: Line 26:
 ==== Scalar Type Declarations ==== ==== Scalar Type Declarations ====
  
-No new reserved words are added. The names ''int'', ''integer'', ''float'', ''string''''bool'' and ''boolean'' are recognised and allowed as type declarations, and prohibited from use as class/interface/trait names (including with ''use'' and ''class_alias'').+No new reserved words are added. The names ''int'', ''float'', ''string'' and ''bool'' are recognised and allowed as type declarations, and prohibited from use as class/interface/trait names (including with ''use'' and ''class_alias'').
  
 The new userland scalar type declarations are implemented internally by calling the Fast Parameter Parsing API functions. The new userland scalar type declarations are implemented internally by calling the Fast Parameter Parsing API functions.
Line 124: Line 125:
 The table shows which types are accepted and converted for scalar type declarations. ''NULL'', arrays and resources are never accepted for scalar type declarations, and so are not included in the table. The table shows which types are accepted and converted for scalar type declarations. ''NULL'', arrays and resources are never accepted for scalar type declarations, and so are not included in the table.
  
-^ Type declaration integer  ^ float    ^ string   boolean ^ object +^ Type declaration int  ^ float    ^ string   bool ^ object 
-^ ''integer''       ^ yes      ^ yes*     ^ yes†     ^ yes     ^ no      ^ +^ ''int''           ^ yes  ^ yes*     ^ yes†     ^ yes  ^ no      ^ 
-^ ''float''         ^ yes      ^ yes      ^ yes†     ^ yes     ^ no      ^ +^ ''float''         ^ yes  ^ yes      ^ yes†     ^ yes  ^ no      ^ 
-^ ''string''        ^ yes      ^ yes      ^ yes      ^ yes     ^ yes‡    ^ +^ ''string''        ^ yes  ^ yes      ^ yes      ^ yes  ^ yes‡    ^ 
-^ ''boolean''       ^ yes      ^ yes      ^ yes      ^ yes     ^ no      ^+^ ''bool''          ^ yes  ^ yes      ^ yes      ^ yes  ^ no      ^
  
 <nowiki>*</nowiki>Only non-NaN floats between ''PHP_INT_MIN'' and ''PHP_INT_MAX'' accepted. (New in PHP 7, see the [[rfc:zpp_fail_on_overflow|ZPP Failure on Overflow]] RFC) <nowiki>*</nowiki>Only non-NaN floats between ''PHP_INT_MIN'' and ''PHP_INT_MAX'' accepted. (New in PHP 7, see the [[rfc:zpp_fail_on_overflow|ZPP Failure on Overflow]] RFC)
Line 144: Line 145:
 These strict type checking rules are used for userland scalar type declarations, and for extension and built-in PHP functions. These strict type checking rules are used for userland scalar type declarations, and for extension and built-in PHP functions.
  
-The one exception is that [[http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2|widening primitive conversion]] is allowed. This means that parameters that declaration ''float'' can also accept ''integer''.+The one exception is that [[http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2|widening primitive conversion]] is allowed for ''int'' to ''float''. This means that parameters that declare ''float'' can also accept ''int''.
  
 <file php widening.php> <file php widening.php>
Line 157: Line 158:
 </file> </file>
  
-In this case, we're passing an ''integer'' to a function that accepts ''float''. The parameter is converted (widened) to float.+In this case, we're passing an ''int'' to a function that accepts ''float''. The parameter is converted (widened) to float. 
 + 
 +No other conversions are allowed. 
 + 
 +==== Error Handler Behavior In Strict Mode ==== 
 + 
 +Currently it's possible to bypass error check failures using an error handler: 
 + 
 +<file php error_handler_fail.php> 
 +<?php 
 +declare(strict_types=1); 
 +set_error_handler(function() { 
 +    return true; 
 +}); 
 + 
 +function foo(int $abc) { 
 +    var_dump($abc); 
 +
 +foo("test"); // string(4) "test" 
 +?> 
 +</file> 
 + 
 +This would defeat the purpose of strict typing.  
 + 
 +Therefore, this RFC proposes to bypass function execution in strict mode if there's a type mismatch error (just like internal functions do today). The implementation is not complete, as this behavior would be superseded by [[rfc:engine_exceptions]] if it passed. Therefore the implementation will wait for the completion of voting on that RFC. 
  
 ===== Example ===== ===== Example =====
Line 244: Line 270:
 } }
  
-var_dump(foobar2());+var_dump(foobar());
 // Catchable fatal error: Return value of foobar() must be of the type integer, float returned // Catchable fatal error: Return value of foobar() must be of the type integer, float returned
 </file> </file>
Line 310: Line 336:
  
 No type declaration for resources is added, as this would prevent moving from resources to objects for existing extensions, which some have already done (e.g. GMP).  No type declaration for resources is added, as this would prevent moving from resources to objects for existing extensions, which some have already done (e.g. GMP). 
- 
-For the integer declaration, both the ''int'' and ''integer'' syntaxes are allowed, and for the boolean declaration, both ''bool'' and ''boolean'' are allowed. This has been done because PHP uses both throughout the manual and error messages, so there is no clear choice of syntax that wouldn't cause problems. While in an ideal world we would not need to support these aliases, the likelihood of people being caught out by ''integer'' or ''boolean'' not working is very high, so I feel we ought to support both the short and long forms of these type names. 
  
 ===== Discussion Points ===== ===== Discussion Points =====
Line 379: Line 403:
 In line with [[http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2|Java]], D and Pascal, this proposal implements widening-conversion rules. This means that integers are accepted for floating point arguments (the example above works). In line with [[http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2|Java]], D and Pascal, this proposal implements widening-conversion rules. This means that integers are accepted for floating point arguments (the example above works).
  
-It however also means that narrowing conversions (float->int) do not work.+It however also means that narrowing conversions (float->int) do not work when passing arguments to functions. 
 + 
 +Note: If you read the Java spec, you'll notice that it does mention narrowing conversions. It only allows them in assignment or explicit casts however. So they do not apply in the case this proposal puts forward.
  
 ==== Weak Should Error On "10 Birds" Style-Strings Passed To Int Parameters ==== ==== Weak Should Error On "10 Birds" Style-Strings Passed To Int Parameters ====
Line 492: Line 518:
 === Current Position === === Current Position ===
  
-There are two problems with using one of the proposed alternates:+The declare system was designed precisely for this style of engine switch. Additionally, it leaves room for extending additional "strict" behaviors in the future.
  
-  * All are generic "strict" which appears ambiguous. What if additional strict modes are added in the future (such as manding the lack of a ''?>'' in a file). +There are also problems with using each of the proposed alternates:
-  * All require either re-interpreting existing syntax or creating new and foreign syntax.+
  
-The declare system was designed precisely for this style of engine switch. Additionally, it leaves room for extending additional "strict" behaviors in the future.+  * ''<?php strict'' 
 + 
 +This is new syntax, which is potentially ambiguous around what "strictness" is being appliedIt limits future compatibility. 
 + 
 +Additionally, it's potentially ambiguous if a file starts with ''<?=strict; 4 ?>''. Is that setting strict mode for a file and outputting 4? Or is it outputting the constant "strict"? Sure, this could be "solved" with a rule that it could only follow ''<?php'', but that starts to get arbitrary and potentially confusing, given the other ways to open PHP tags. 
 + 
 +  * ''<?php-strict'' 
 + 
 +This opens the door for potential code disclosure vulnerability if run on an earlier version of PHP (since the ''<?php-strict'' opening tag won't be interpreted properly). 
 + 
 +  * ''use strict;'' 
 + 
 +Re-using namespaces to affect runtime is weird. Not to mention what's the expected behavior of block mode: 
 + 
 +<file php use_strict.php> 
 +<?php 
 +namespace Foo { 
 +    use strict; 
 +
 + 
 +namespace { 
 +    bar(); 
 +
 +?> 
 +</file> 
 + 
 +is bar() called in strict mode? Or in non-strict mode? 
 + 
 +  * ''<?php %%//%% strict'' (HHVM style) 
 + 
 +Comments should not affect runtime behavior. HHVM uses it as they need to affect behavior while remaining compatible with PHP. We do not have that problem. 
 + 
 +  * ''declare(strict=true)'' (exactly as in v0.3) 
 + 
 +Which had a number of people against it, with arguments about the odd behavior of declare in blocks, etc. It does not respect scope, so calling it in one function would transparently effect all future functions in the file. 
 + 
 +  * ''strict namespace'' 
 + 
 +<file php strict_namespace.php> 
 +<?php 
 +strict namespace Foo { 
 + 
 +
 + 
 +namespace { 
 +    bar(); 
 +
 +?> 
 +</file> 
 + 
 +This has the same issues as use strict above. However, it also seems to imply that the namespace is strict, where it's only the declarations in the file that are.
  
 ==== Why Not Allow Block-Mode For Declare ==== ==== Why Not Allow Block-Mode For Declare ====
Line 516: Line 591:
 Allowing strict "blocks" can create situations where a single file uses several "type modes". This can hamper readability and make working on typed code significantly harder. Allowing strict "blocks" can create situations where a single file uses several "type modes". This can hamper readability and make working on typed code significantly harder.
  
-Therefore, this proposal explicitly disallows changing the type mode anywhere within the file except the first line. Since the first line is the only allowed type change, block mode does not make sense (as there could only ever be a single block in the file). +Therefore, this proposal explicitly disallows changing the type mode anywhere within the file except the first line. Since the first line is the only allowed type change, block mode does not make sense (as there could only ever be a single block in the file)
 + 
 +Additionally, some technical limitations do make it significantly more difficult: [[http://news.php.net/php.internals/83356|Email describing limitiations]].
  
 ==== Internal Functions Do Not Have Declared Return Types ==== ==== Internal Functions Do Not Have Declared Return Types ====
Line 542: Line 619:
 Currently, there's no mandate for fully typing all functions (even in strict mode). Therefore, there's no functional difference between ''mixed'' and a non-type-declared paramter. For that reason, addition of a ''mixed'' type is outside of the scope for this proposal. Currently, there's no mandate for fully typing all functions (even in strict mode). Therefore, there's no functional difference between ''mixed'' and a non-type-declared paramter. For that reason, addition of a ''mixed'' type is outside of the scope for this proposal.
  
 +==== Why Not Add An INI Setting For Default Mode ====
 +
 +It's been asked for the ability to switch the default mode from "weak" to "strict" by a mechanism (ini or compile time flag, etc).
 +
 +=== Current Position ===
 +
 +This proposal takes the opinion that behavior modifying switches like ini settings are a death-toll to portability and well designed languages should not change behavior based on "global settings". Therefore, switching strict modes will remain a per-file setting for this proposal.
 +
 +==== Type Aliases Should Not Be Supported ====
 +
 +The original proposal had two additional type aliases supported: ''integer'' and ''boolean''.
 +
 +=== Current Position ===
 +
 +This proposal takes the stance that there should be one obvious type. Therefore, no aliases are supported.
 +
 +==== This Proposal Should Have Multiple Vote Options ====
 +
 +Several people have proposed that this proposal should have 3 or 4 vote options (No, Weak Only, Strict Only, Weak + Strict).
 +
 +=== Current Position ===
 +https://wiki.php.net/rfc/reserve_more_types_in_php_7
 +This is not a two-part proposal. The proposal is of a unified system that was designed to work together. As such, neither part (weak-only or strict-only) is designed to stand on its own without the other part.
 +
 +Therefore, it only makes sense to vote on this proposal as a whole. Therefore, the voting options this RFC will present will be: ''Yes'' and ''No''.
 +
 +==== Integer Overflow To Float Behavior ====
 +
 +Currently, certain integer operations will result in an overflow to a floating point value. Consider the following code:
 +
 +<file php integer_overflow.php>
 +<?php
 +var_dump(2 ** 61); // int(2305843009213693952)
 +var_dump(2 ** 64); // float(1.844674407371E+19)
 +</file>
 +
 +This can result in an error when passing the result of an operation to another function expecting an integer.
 +
 +There are two prime ways of handling this issue:
 +
 +  * Allow ''float'' -> ''int'' promotion (narrowing)
 +  * Error at runtime.
 +
 +=== Current Position ===
 +
 +Allowing for "narrowing" (truncating the float back to the closest integer) would result in hard to detect bugs. 
 +
 +Therefore, a runtime error that the overflow occurred is the most appropriate thing to do.
 +
 +Therefore, the position of this proposal is that overflow situations should generate a runtime error. If you need overflow safety, you should be using a library like GMP.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
  
-''int'', ''integer'', ''float'', ''string''''bool'' and ''boolean'' are no longer permitted as class/interface/trait names (including with ''use'' and ''class_alias'').+''int'', ''float'', ''string'' and ''bool'' are no longer permitted as class/interface/trait names (including with ''use'' and ''class_alias'').
  
 Because the weak type-checking rules for scalar declarations are quite permissive in the values they accept and behave similarly to PHP's type juggling for operators, it should be possible for existing userland libraries to add scalar type declarations without breaking compatibility. Because the weak type-checking rules for scalar declarations are quite permissive in the values they accept and behave similarly to PHP's type juggling for operators, it should be possible for existing userland libraries to add scalar type declarations without breaking compatibility.
Line 553: Line 680:
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
  
-This is proposed for the next PHP x, currently PHP 7. The acceptance for said version will depend on timing of the vote completion.+This proposal targets the 7.0 release of PHP.
  
 ===== RFC Impact ===== ===== RFC Impact =====
Line 576: Line 703:
  
 As this is a language change, this RFC requires a 2/3 majority to pass. As this is a language change, this RFC requires a 2/3 majority to pass.
 +
 +<doodle title="Accept Scalar Type Declarations With Optional Strict Mode?" auth="ircmaxell" voteType="single" closed="true">
 +   * Yes
 +   * No
 +</doodle>
 +
 +This vote is opened on February 26th, 2015 and will close March 16th at 21:00 UTC as announced on list.
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
Line 597: Line 731:
 ===== Changelog ===== ===== Changelog =====
  
 +  * v0.5.3 Change version target back and add line about bypassing function execution on type error in strict mode
 +  * v0.5.2 Change version target
 +  * v0.5.1 Remove aliases from proposal
   * v0.5 Fork from Andrea's original proposal. Change declare behavior. Add int->float (primitive type widening).   * v0.5 Fork from Andrea's original proposal. Change declare behavior. Add int->float (primitive type widening).
rfc/scalar_type_hints_v5.txt · Last modified: 2018/10/17 11:38 by carusogabriel