rfc:explicit_send_by_ref
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:explicit_send_by_ref [2017/12/05 21:03] – nikic | rfc:explicit_send_by_ref [2022/01/25 18:21] (current) – Move to inactive ilutov | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Explicit | + | ====== PHP RFC: Allow explicit |
* Date: 2017-12-02 | * Date: 2017-12-02 | ||
* Author: Nikita Popov < | * Author: Nikita Popov < | ||
- | * Proposed for: PHP 7.3 | + | * Proposed for: PHP 8.0 |
* Implementation: | * Implementation: | ||
- | * Status: | + | * Status: |
===== Introduction ===== | ===== Introduction ===== | ||
- | Currently | + | By-reference |
Consider the following example of an '' | Consider the following example of an '' | ||
Line 44: | Line 44: | ||
The requirement that the reference is marked at both the definition- and call-site makes this feature different from the call-site pass-by-reference that was used in PHP 4. | The requirement that the reference is marked at both the definition- and call-site makes this feature different from the call-site pass-by-reference that was used in PHP 4. | ||
- | Of course, it remains possible to not explicitly mark reference-passing at the call-site. | + | By default, the use of a call-site |
===== Motivation ===== | ===== Motivation ===== | ||
- | The motivation for this proposal boils down to making it simpler to understand code, both for programmers and for static analyzers. | + | The motivation for this proposal boils down to making it simpler to understand code: For programmers, for static analyzers |
As a simple example, consider the following two calls, which look deceptively similar: | As a simple example, consider the following two calls, which look deceptively similar: | ||
Line 59: | Line 59: | ||
In both cases '' | In both cases '' | ||
- | Under this proposal, | + | With this proposal, |
<code php> | <code php> | ||
Line 97: | Line 97: | ||
Does this code use an uninitialized variable '' | Does this code use an uninitialized variable '' | ||
- | While static analyzers in IDEs and CI systems will make reasonable assumptions in this case, the PHP implementation itself does not have this luxury. In fact, our inability to determine at compile-time whether a certain argument is passed by-value or by-reference is one of the most significant obstacles in our ability to analyze and optimize compiled code. The runtime dispatch between by-value and by-reference passing also adds significant complexity to the Zend VM, with at least 7 opcodes dedicated to only this task. | + | While static analyzers in IDEs and CI systems will make reasonable assumptions in this case, the PHP implementation itself does not have this luxury. In fact, our inability to determine at compile-time whether a certain argument is passed by-value or by-reference is one of the most significant obstacles in our ability to analyze and optimize compiled code. The runtime dispatch between by-value and by-reference passing also adds significant complexity to the Zend VM, with at 9 (!!) opcodes dedicated to this task. |
- | + | ||
- | This proposal does not resolve this issue, because it introduces an entirely optional feature. The previous syntax where pass-by-reference is not explicitly marked will continue to work. We may want to deprecate and remove it in the future, but this RFC does not propose this, as it is a quite significant change. | + | |
===== Detailed proposal ===== | ===== Detailed proposal ===== | ||
Line 149: | Line 147: | ||
</ | </ | ||
- | Apart from these additional error checks, the call-site reference-passing annotation does not change | + | Apart from these additional error checks, the call-site reference-passing annotation does not affect execution semantics in any way. |
+ | |||
+ | ==== Mode with required call-site annotations ==== | ||
+ | |||
+ | This section depends on the outcome of the [[https:// | ||
+ | |||
+ | While optionally annotating by-reference passing already helps readability, | ||
+ | |||
+ | <code php> | ||
+ | declare(require_explicit_send_by_ref=1); | ||
+ | |||
+ | function inc(& | ||
+ | |||
+ | $i = 0; | ||
+ | inc($i); | ||
+ | // Uncaught Error: Cannot pass parameter 1 by reference | ||
+ | </ | ||
+ | |||
+ | If the argument is a prefer-ref argument of an internal function, then adding the ''&'' | ||
+ | |||
+ | Just like '' | ||
+ | |||
+ | ==== Forwarding references in __call, call_user_func and similar ==== | ||
+ | |||
+ | The '' | ||
+ | |||
+ | <code php> | ||
+ | class Incrementor { | ||
+ | public function inc(& | ||
+ | $i++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class ForwardCalls { | ||
+ | private $object; | ||
+ | public function __construct($object) { | ||
+ | $this-> | ||
+ | } | ||
+ | public function __call(string $method, array $args) { | ||
+ | return $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $forward = new ForwardCalls(new Incrementor); | ||
+ | $i = 0; | ||
+ | $forward-> | ||
+ | var_dump($i); | ||
+ | </ | ||
+ | |||
+ | The above code silently " | ||
+ | |||
+ | The explicit call-site annotation can be used to allow passing the variable by reference: | ||
+ | |||
+ | <code php> | ||
+ | $forward = new ForwardCalls(new Incrementor); | ||
+ | $i = 0; | ||
+ | $forward-> | ||
+ | var_dump($i); | ||
+ | </ | ||
+ | |||
+ | This will make the corresponding element in '' | ||
+ | |||
+ | Similarly, '' | ||
+ | |||
+ | <code php> | ||
+ | function inc(& | ||
+ | |||
+ | $i = 0; | ||
+ | call_user_func(' | ||
+ | // Warning: inc() expects argument #1 ($i) to be passed by reference, value given | ||
+ | var_dump($i); | ||
+ | |||
+ | $i = 0; | ||
+ | call_user_func(' | ||
+ | var_dump($i); | ||
+ | </ | ||
+ | |||
+ | Both of these features are achieved by introducing a new internal argument passing mode '' | ||
+ | |||
+ | ==== Differences to the removed " | ||
+ | |||
+ | In PHP 4 (and available via deprecated '' | ||
+ | |||
+ | <code php> | ||
+ | function inc($num) { $num++; } | ||
+ | |||
+ | $i = 0; | ||
+ | inc(& | ||
+ | </ | ||
+ | |||
+ | This was very problematic, | ||
+ | |||
+ | PHP 5 moved towards specifying by-reference passing at the declaration-site, | ||
+ | |||
+ | This proposal differs from both in that it requires the by-reference annotation at **both** the declaration-site and the call-site. It is extremely unfortunate that this hasn't been done when the original migration of the by-reference passing system happened, as it could have avoided a lot of unnecessary code churn while arriving at a better system. Given this past mistake, the next best thing we can do is address it now. | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
- | None. This use of this feature is optional. | + | None. The use of this feature is optional, and the backwards-incompatible part is opt-in. |
===== Other languages ===== | ===== Other languages ===== | ||
Line 169: | Line 261: | ||
With the notable exception of C++ (which most likely inspired our current reference-passing syntax), reference annotations are required both at the declaration and the call-site. | With the notable exception of C++ (which most likely inspired our current reference-passing syntax), reference annotations are required both at the declaration and the call-site. | ||
- | In languages where references are first-class types (rather than a special feature of calls specifically), | + | In languages where references are first-class types (rather than a special feature of calls specifically), |
===== Future Scope ===== | ===== Future Scope ===== | ||
- | Currently PHP abuses | + | ==== inout / out parameters ==== |
+ | |||
+ | Currently PHP uses by-reference passing as a way to implement '' | ||
For example the auto-initialization behavior of references is only desired in the case of '' | For example the auto-initialization behavior of references is only desired in the case of '' | ||
Line 179: | Line 273: | ||
===== Vote ===== | ===== Vote ===== | ||
- | This proposal is a language-change and requires a 2/3 supermajority to pass. | + | Add support for optional call-site by-reference passing annotations? |
rfc/explicit_send_by_ref.txt · Last modified: 2022/01/25 18:21 by ilutov