rfc:explicit_send_by_ref

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
rfc:explicit_send_by_ref [2020/02/20 10:27] nikicrfc:explicit_send_by_ref [2022/01/25 18:21] (current) – Move to inactive ilutov
Line 1: Line 1:
-====== PHP RFC: Explicit call-site pass-by-reference ======+====== PHP RFC: Allow explicit call-site pass-by-reference annotation ======
   * Date: 2017-12-02   * Date: 2017-12-02
   * Author: Nikita Popov <nikic@php.net>   * Author: Nikita Popov <nikic@php.net>
   * Proposed for: PHP 8.0   * Proposed for: PHP 8.0
   * Implementation: https://github.com/php/php-src/pull/2958   * Implementation: https://github.com/php/php-src/pull/2958
-  * Status: Under Discussion+  * Status: Inactive
  
 ===== Introduction ===== ===== Introduction =====
Line 166: Line 166:
  
 If the argument is a prefer-ref argument of an internal function, then adding the ''&'' annotation will pass it by reference, while not adding it will pass it by value. Outside this mode, the passing behavior would instead be determined by the VM kind of the argument operand. If the argument is a prefer-ref argument of an internal function, then adding the ''&'' annotation will pass it by reference, while not adding it will pass it by value. Outside this mode, the passing behavior would instead be determined by the VM kind of the argument operand.
 +
 +Just like ''strict_types'', the ''require_explicit_send_by_ref'' option only affects call-sites inside the file. Whether the function was declared in a file with ''require_explicit_send_by_ref'' enabled or not does not matter, only the used mode at the call-site matters.
 +
 +==== Forwarding references in __call, call_user_func and similar ====
 +
 +The ''%%__call()%%'' and ''%%__callStatic()%%'' magic methods can be used to forward calls, but this does not work properly with by-reference arguments:
 +
 +<code php>
 +class Incrementor {
 +    public function inc(&$i) {
 +        $i++;
 +    }
 +}
 +
 +class ForwardCalls {
 +    private $object;
 +    public function __construct($object) {
 +        $this->object = $object;
 +    }
 +    public function __call(string $method, array $args) {
 +        return $this->object->$method(...$args);
 +    }
 +}
 +
 +$forward = new ForwardCalls(new Incrementor);
 +$i = 0;
 +$forward->inc($i);
 +var_dump($i); // int(0)
 +</code>
 +
 +The above code silently "works", but the variable ''$i'' will not actually get passed by reference. A by-reference pass does occur at the ''%%$this->object->$method(...$args)%%'' call, but at this point the value stored in ''$args'' and the variable ''$i'' have no relation to each other.
 +
 +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->inc(&$i);
 +var_dump($i); // int(1)
 +</code>
 +
 +This will make the corresponding element in ''$args'' be a reference, which the argument unpack then passes on to the called function.
 +
 +Similarly, ''call_user_func()'' can now be used to call functions that accept by-reference parameters:
 +
 +<code php>
 +function inc(&$i) { $i++; }
 +
 +$i = 0;
 +call_user_func('inc', $i);
 +// Warning: inc() expects argument #1 ($i) to be passed by reference, value given
 +var_dump($i); // int(0)
 +
 +$i = 0;
 +call_user_func('inc', &$i);
 +var_dump($i); // int(1)
 +</code>
 +
 +Both of these features are achieved by introducing a new internal argument passing mode ''prefer-val''. Just like ''prefer-ref'' it accepts both by-value and by-reference, but prefers by-value passing unless by-reference passing is forced by a call-site annotation.
  
 ==== Differences to the removed "call-time pass-by-reference" feature ==== ==== Differences to the removed "call-time pass-by-reference" feature ====
rfc/explicit_send_by_ref.1582194442.txt.gz · Last modified: 2020/02/20 10:27 by nikic