rfc:scalar_type_hints
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:scalar_type_hints [2015/01/25 00:53] – Short form ajf | rfc:scalar_type_hints [2017/09/22 13:28] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Scalar Type Hints ====== | ====== PHP RFC: Scalar Type Hints ====== | ||
- | * Version: 0.2.3 | + | * Version: 0.3.1 |
- | * Date: 2014-12-14 (initial draft; put Under Discussion 2014-12-31; version 0.2 created 2015-01-13) | + | * Date: 2014-12-14 (initial draft; put Under Discussion 2014-12-31; version 0.2 created 2015-01-13; withdrawn 2015-02-15) |
* Author: Andrea Faulds, ajf@ajf.me | * Author: Andrea Faulds, ajf@ajf.me | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
===== Summary ===== | ===== Summary ===== | ||
- | This RFC proposes the addition of four type hints for scalar types: '' | + | This RFC proposes the addition of four type hints for scalar types: '' |
- | This RFC further proposes the addition of a new optional per-file directive, '' | + | This RFC further proposes the addition of a new optional per-file directive, '' |
With these two features, it is hoped that more correct and self-documenting PHP programs can be written. | With these two features, it is hoped that more correct and self-documenting PHP programs can be written. | ||
Line 87: | Line 87: | ||
</ | </ | ||
- | The strict type checking mode also affects extension and built-in PHP functions: | + | The directive affects all function calls in the file (or '' |
+ | |||
+ | <file php strict_mix.php> | ||
+ | <?php | ||
+ | require " | ||
+ | |||
+ | // implicitly weakly type-checked code (default) | ||
+ | $nelly = new ElePHPant(12345, | ||
+ | |||
+ | declare(strict_types=1) { | ||
+ | // explicitly strictly type-checked code | ||
+ | |||
+ | $nelly = new ElePHPant(12345, | ||
+ | // Catchable fatal error: Argument 1 passed to ElePHPant:: | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This applies equally to nested function calls, which also use the strictness setting of the file: | ||
+ | |||
+ | <file php strict_mix2.php> | ||
+ | <?php | ||
+ | require " | ||
+ | |||
+ | // implicitly weakly type-checked code (default) | ||
+ | function makeEllie() { | ||
+ | return new ElePHPant(42, | ||
+ | } | ||
+ | |||
+ | makeEllie(); | ||
+ | |||
+ | declare(strict_types=1) { | ||
+ | // explicitly strictly type-checked code | ||
+ | |||
+ | makeEllie(); | ||
+ | |||
+ | function makeEllie_strict() { | ||
+ | return new ElePHPant(42, | ||
+ | } | ||
+ | |||
+ | makeEllie_strict(); | ||
+ | } | ||
+ | |||
+ | // implicitly weakly type-checked code, again | ||
+ | |||
+ | makeEllie_strict(); | ||
+ | </ | ||
+ | |||
+ | In addition to userland functions, the strict type checking mode also affects extension and built-in PHP functions: | ||
<file php main4.php> | <file php main4.php> | ||
Line 96: | Line 143: | ||
$foo = sin(1); | $foo = sin(1); | ||
// Catchable fatal error: sin() expects parameter 1 to be float, integer given | // Catchable fatal error: sin() expects parameter 1 to be float, integer given | ||
+ | </ | ||
+ | |||
+ | Scalar type hints would also work for return values, as does strict type checking mode: | ||
+ | |||
+ | <file php returns.php> | ||
+ | <?php | ||
+ | |||
+ | function foobar(): int { | ||
+ | return 1.0; | ||
+ | } | ||
+ | |||
+ | var_dump(foobar()); | ||
+ | |||
+ | declare(strict_types=1) { | ||
+ | function foobar2(): int { | ||
+ | return 1.0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var_dump(foobar2()); | ||
+ | // Catchable fatal error: Return value of foobar() must be of the type integer, float returned | ||
+ | </ | ||
+ | |||
+ | However, there is a key difference between parameter and return type hints. The type-checking mode used for parameters is the one used by the file containing the function call, while the type-checking mode used for return values is the one used by the file containing the return statement (i.e. the file defining the function). So: | ||
+ | |||
+ | <file php returns.php> | ||
+ | <?php | ||
+ | |||
+ | declare(strict_types=1) { | ||
+ | function foobar3(): int { | ||
+ | return 1.0; // error, regardless of where it is called from | ||
+ | } | ||
+ | |||
+ | foobar3(); // error | ||
+ | } | ||
+ | |||
+ | foobar3(); // also error | ||
</ | </ | ||
Line 102: | Line 186: | ||
==== History ==== | ==== History ==== | ||
- | PHP has had parameter type hints for class names since PHP 5.0, arrays since PHP 5.1 and callables since PHP 5.4. These type hints allow the PHP runtime to ensure that correctly-typed arguments are passed to functions, and make function signatures more informative. Unfortunately, | + | PHP has had parameter type hints for interface and class names since PHP 5.0, arrays since PHP 5.1 and callables since PHP 5.4. These type hints allow the PHP runtime to ensure that correctly-typed arguments are passed to functions, and make function signatures more informative. Unfortunately, |
There have been some previous attempts at adding scalar type hints, such as the [[rfc: | There have been some previous attempts at adding scalar type hints, such as the [[rfc: | ||
Line 110: | Line 194: | ||
* Its attempt at " | * Its attempt at " | ||
- | In creating this RFC attempts | + | In creating this RFC, I have attempted |
==== Weak typing and strict typing ==== | ==== Weak typing and strict typing ==== | ||
- | There are two major approaches to how to check parameter | + | There are two major approaches to how to check parameter |
* Strict type checking, which is used by many popular programming languages, particularly ones which are statically-typed, | * Strict type checking, which is used by many popular programming languages, particularly ones which are statically-typed, | ||
Line 128: | Line 212: | ||
throw new Exception(" | throw new Exception(" | ||
} | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Similarly, in both approaches, a function will always return exactly the return type it claims to: | ||
+ | |||
+ | <code php> | ||
+ | function barfoo(): int { | ||
+ | /* ... */ | ||
+ | } | ||
+ | if (!is_int(barfoo())) { | ||
+ | throw new Exception(" | ||
} | } | ||
</ | </ | ||
Line 176: | Line 271: | ||
==== strict_types declare() directive ==== | ==== strict_types declare() directive ==== | ||
- | By default, all PHP files are in weak type-checking mode. A new '' | + | By default, all PHP files are in weak type-checking mode. A new '' |
- | This directive also supports the '' | + | This directive also supports the '' |
Like the '' | Like the '' | ||
- | The directive is entirely compile-time and affects any function call, including those within a function or method. For example: | + | The directive is entirely compile-time and cannot be controlled at runtime. It works by setting a flag on the opcodes for function calls (for parameter type hints) and return type checks (for return type hints). |
+ | |||
+ | === Parameter type hints === | ||
+ | |||
+ | The directive | ||
<file php strict_types_scope.php> | <file php strict_types_scope.php> | ||
<?php | <?php | ||
- | declare(strict_types=TRUE) { | + | declare(strict_types=1) { |
foo(); // strictly type-checked function call | foo(); // strictly type-checked function call | ||
Line 214: | Line 313: | ||
</ | </ | ||
- | Whether or not the function being called was declared in a file that uses strict or weak type checking is entirely | + | Whether or not the function being called was declared in a file that uses strict or weak type checking is irrelevant. The type checking mode depends on the file where the function is called. |
- | ==== Behaviour of weakly type-checked function | + | === Return type hints === |
+ | |||
+ | The directive affects any return statement in any function or method within a file. For example: | ||
+ | |||
+ | <file php strict_types_scope.php> | ||
+ | <?php | ||
+ | |||
+ | declare(strict_types=1) { | ||
+ | function foobar(): int { | ||
+ | return 1.0; // strictly type-checked return | ||
+ | } | ||
+ | |||
+ | class baz { | ||
+ | function foobar(): int { | ||
+ | return 1.0; // strictly type-checked return | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function foobar(): int { | ||
+ | return 1.0; // weakly type-checked | ||
+ | } | ||
+ | |||
+ | class baz { | ||
+ | | ||
+ | return 1.0; // weakly type-checked return | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Unlike parameter type hints, the type checking mode used for return types depends on the file where the function is defined, not where the function is called. This is because returning the wrong type is a problem with the callee, while passing the wrong type is a problem with the caller. | ||
+ | |||
+ | ==== Behaviour of weak type checks | ||
A weakly type-checked call to an extension or built-in PHP function has exactly the same behaviour as it did in previous PHP versions. | A weakly type-checked call to an extension or built-in PHP function has exactly the same behaviour as it did in previous PHP versions. | ||
- | The weak type checking rules for the new scalar type hints are mostly the same as those of extension and built-in PHP functions. The only exception to this is the handling of '' | + | The weak type checking rules for the new scalar type hints are mostly the same as those of extension and built-in PHP functions. The only exception to this is the handling of '' |
For the reference of readers who may not be familiar with PHP's existing weak scalar parameter type rules, the following brief summary is provided. | For the reference of readers who may not be familiar with PHP's existing weak scalar parameter type rules, the following brief summary is provided. | ||
Line 238: | Line 369: | ||
‡Only if it has a '' | ‡Only if it has a '' | ||
- | ==== Behaviour of strictly | + | ==== Behaviour of strict |
A strictly type-checked call to an extension or built-in PHP function changes the behaviour of '' | A strictly type-checked call to an extension or built-in PHP function changes the behaviour of '' | ||
- | The strict type checking rules are quite straightforward: | + | The strict type checking rules are quite straightforward: |
These strict type checking rules are used for userland scalar type hints, and for extension and built-in PHP functions. | These strict type checking rules are used for userland scalar type hints, and for extension and built-in PHP functions. | ||
- | |||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 269: | Line 399: | ||
This doesn' | This doesn' | ||
- | When the strict type-checking mode isn't in use (which is the default), function calls behave identically to previous PHP versions. | + | When the strict type-checking mode isn't in use (which is the default), function calls to built-in and extension PHP functions |
===== Open Issues ===== | ===== Open Issues ===== | ||
- | There are two open issues | + | There is currently an open issue related to naming, described below. This will go to a vote. |
- | * Currently, this RFC and patch allows the aliases '' | + | This RFC and patch allows the aliases '' |
- | * Should the scalar type hint names be prohibited from use as class names? The patch currently prohibits this (< | + | ==== TODO ==== |
- | * The patch doesn' | + | |
- | * Should the '' | + | * Produce |
+ | * Return types need more tests. | ||
===== Future Scope ===== | ===== Future Scope ===== | ||
- | |||
- | If return types are added, such as with the [[rfc: | ||
Because scalar type hints guarantee that a passed argument will be of a certain type within a function body (at least initially), this could be used in the Zend Engine for optimisations. For example, if a function takes two '' | Because scalar type hints guarantee that a passed argument will be of a certain type within a function body (at least initially), this could be used in the Zend Engine for optimisations. For example, if a function takes two '' | ||
- | ===== Proposed | + | In discussions around this RFC, the '' |
+ | |||
+ | Another issue that came up is PHP's lack of a typehint for numbers (which also came up with the previous Scalar Type Hinting with Cast RFC). I plan to propose a '' | ||
+ | |||
+ | ===== Vote ===== | ||
+ | |||
+ | As this is a language change, this RFC requires a 2/3 majority to pass. Voting | ||
+ | |||
+ | ==== Main ==== | ||
+ | |||
+ | This vote is for the RFC itself. | ||
+ | |||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
+ | |||
+ | ==== Type aliases ==== | ||
+ | |||
+ | This second vote is to solve the open issue regarding the '' | ||
+ | |||
+ | <doodle title=" | ||
+ | * Allow synonyms | ||
+ | * Reserve synonyms and produce error message when used | ||
+ | * Do not reserve | ||
+ | </ | ||
+ | |||
+ | ==== Reserve for future use ==== | ||
+ | |||
+ | This final vote is in case the RFC fails to pass. It's a 2/3 majority-required backwards compatibility-breaking language change, which is to reserve the type hint names proposed by the RFC, so that a future RFC could implement scalar type hints without requiring a backwards compatibility break. The type names reserved include the synonyms '' | ||
- | As this is a language change, this RFC requires a 2/3 majority to pass. It will be a Yes/No vote. | + | <doodle title=" |
+ | | ||
+ | * No | ||
+ | </doodle> | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | There is a working, but incomplete | + | There is a working, but possibly buggy php-src pull request with tests here: https:// |
- | There is no language specification patch. | + | There is no language specification patch as yet. |
===== Implementation ===== | ===== Implementation ===== | ||
Line 310: | Line 470: | ||
===== Changelog ===== | ===== Changelog ===== | ||
+ | * v0.3.1 - Noted '' | ||
+ | * v0.3 - Return types support | ||
* v0.2.3 - '' | * v0.2.3 - '' | ||
* v0.2.2 - Follow robustness principle for return types under Future Scope | * v0.2.2 - Follow robustness principle for return types under Future Scope |
rfc/scalar_type_hints.1422147213.txt.gz · Last modified: 2017/09/22 13:28 (external edit)