rfc:variadics

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:variadics [2013/08/28 15:58] nikicrfc:variadics [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 2: Line 2:
   * Date: 2013-08-27   * Date: 2013-08-27
   * Author: Nikita Popov <nikic@php.net>   * Author: Nikita Popov <nikic@php.net>
-  * Status: Under Discussion +  * Status: Implemented in PHP 5.6 ([[https://github.com/php/php-src/commit/0d7a6388663b76ebed6585ac92dfca5ef65fa7af|git:0d7a6388]])
-  * Proposed for: PHP 5.6+
   * Patch: https://github.com/php/php-src/pull/421   * Patch: https://github.com/php/php-src/pull/421
 +  * Mailing list discussion: http://markmail.org/message/uhewgv7zaagkgzdv
  
 ===== Proposal ===== ===== Proposal =====
Line 49: Line 49:
  
 The ''%%...$params%%'' syntax indicates that this is a variadic function and that all arguments after ''$query'' should be put into the ''$params'' array. Using the new syntax both of the issues mentioned above are solved. The ''%%...$params%%'' syntax indicates that this is a variadic function and that all arguments after ''$query'' should be put into the ''$params'' array. Using the new syntax both of the issues mentioned above are solved.
 +
 +==== Population of variadic parameter ====
 +
 +The following example shows how the variadic parameter ''%%...$params%%'' is populated depending on the number of passed arguments:
 +
 +<code php>
 +function fn($reqParam, $optParam = null, ...$params) {
 +    var_dump($reqParam, $optParam, $params);
 +}
 +
 +fn(1);             // 1, null, []
 +fn(1, 2);          // 1, 2, []
 +fn(1, 2, 3);       // 1, 2, [3]
 +fn(1, 2, 3, 4);    // 1, 2, [3, 4]
 +fn(1, 2, 3, 4, 5); // 1, 2, [3, 4, 5]
 +</code>
 +
 +''$params'' will be an empty array if the number of passed arguments is smaller than the number of declared parameters. Any further arguments will be added to the ''$params'' array (in the order in which they were passed). The ''$params'' array is using continuous zero-based indices.
  
 ==== By-reference capture ==== ==== By-reference capture ====
Line 58: Line 76:
 <code php> <code php>
 class MySQL implements DB { class MySQL implements DB {
-    public function prepare($query, &... $params) {+    public function prepare($query, &...$params) {
         $stmt = $this->pdo->prepare($query);         $stmt = $this->pdo->prepare($query);
         foreach ($params as $i => &$param) {         foreach ($params as $i => &$param) {
Line 81: Line 99:
  
 <code php> <code php>
-function array_merge(array... $arrays) { /* ... */ }+function array_merge(array ...$arrays) { /* ... */ }
 </code> </code>
  
-PHP would make sure that all arguments are actually arrays. This also works for all other typehints like ''%%callable... $callbacks%%'' or ''%%Route... $routes%%''.+PHP would make sure that all arguments are actually arrays. This also works for all other typehints like ''%%callable ...$callbacks%%'' or ''%%Route ...$routes%%''.
  
 ==== Prototype checks ==== ==== Prototype checks ====
Line 133: Line 151:
 public function query($query, array ...$params) public function query($query, array ...$params)
 public function query($query, callable $extraParam = null, array ...$params) public function query($query, callable $extraParam = null, array ...$params)
 +</code>
 +
 +==== Syntactic restrictions ====
 +
 +There may be only one variadic parameter and it needs to be the last parameter of the function. A variadic parameter may not have a default value.
 +
 +As such all of the following are invalid:
 +
 +<code php>
 +function fn(...$args, $arg)
 +function fn(...$args1, ...$args2)
 +function fn($arg, ...$args = [])
 </code> </code>
  
Line 153: Line 183:
   * ''%%function fn($arg, &...$args)%%'': Do the capture by reference   * ''%%function fn($arg, &...$args)%%'': Do the capture by reference
   * ''%%function fn($arg, array ...$args)%%'': Enforce that all variadic arguments are arrays (or some other typehint)   * ''%%function fn($arg, array ...$args)%%'': Enforce that all variadic arguments are arrays (or some other typehint)
-  * ''%%function fn($arg, array& ...$args)%%'': Combine both - variadic arguments are arrays that are captured by-reference+  * ''%%function fn($arg, array &...$args)%%'': Combine both - variadic arguments are arrays that are captured by-reference
  
 The advantages of the syntax are: The advantages of the syntax are:
Line 162: Line 192:
   * Types can be checked with a typehint (rather than a manual loop)   * Types can be checked with a typehint (rather than a manual loop)
   * Variadic prototypes can be enforce in interfaces / by inheritance   * Variadic prototypes can be enforce in interfaces / by inheritance
 +
 +===== Backwards compatibility =====
 +
 +==== Userland ====
 +
 +This change does not break backwards compatibility for userland code.
 +
 +In particular, this RFC does not propose to deprecate or remove the ''func_get_args()'' family of functions, at least not any time soon.
      
-===== Impact on internals =====+==== Internal ====
  
 The ''pass_rest_by_ref'' argument of ''ZEND_BEGIN_ARG_INFO'' and ''ZEND_BEING_ARG_INFO_EX'' is no longer used. Instead functions can declare a variadic argument in the arginfo using ''ZEND_ARG_VARIADIC_INFO''. The ''pass_rest_by_ref'' argument of ''ZEND_BEGIN_ARG_INFO'' and ''ZEND_BEING_ARG_INFO_EX'' is no longer used. Instead functions can declare a variadic argument in the arginfo using ''ZEND_ARG_VARIADIC_INFO''.
  
-For example, this is how the arginfo for ''sscanf'' changed:+For example, this is how the arginfo for ''sscanf()'' changed:
  
 <code c> <code c>
Line 187: Line 225:
 It would theoretically be possible to retain support for ''pass_rest_by_ref'' (by automatically generating a variadic arg), but as this is an exceedingly rarely used feature I don't think this is necessary. All usages of it in php-src have been replaced. It would theoretically be possible to retain support for ''pass_rest_by_ref'' (by automatically generating a variadic arg), but as this is an exceedingly rarely used feature I don't think this is necessary. All usages of it in php-src have been replaced.
  
-Apart from this the change should be transparent from an internals point of view. Macros like ''ARG_MUST_BE_SENT_BY_REF'' +Apart from this the change should be transparent from an internals point of view. Macros like ''ARG_MUST_BE_SENT_BY_REF'' continue to work.
-continue to work+
-   +
-===== Backwards Compatability ===== +
- +
-This change does not break backwards compatability for userland code.+
  
 ===== Discussion ===== ===== Discussion =====
Line 205: Line 238:
  
   * ''%%$args...%%''. With ref-modifier (''%%&$args...%%'') this does not show well that the individual arguments are references, rather than ''$args'' itself. With typehint (''%%array $args...%%'') it also looks like the typehint applies to ''$args'' itself rather than all variadic arguments.   * ''%%$args...%%''. With ref-modifier (''%%&$args...%%'') this does not show well that the individual arguments are references, rather than ''$args'' itself. With typehint (''%%array $args...%%'') it also looks like the typehint applies to ''$args'' itself rather than all variadic arguments.
-  * ''*$args''. This is the syntax that both Ruby and Python use. For PHP this does not work well because ''*$'' is a weird combination. It gets worse with a by-reference capture: ''&*$args''. This looks like a random sequences of special characters.+  * ''*$args''. This is the syntax that both Ruby and Python use. For PHP this does not work well because ''*$'' is a weird combination. It gets worse with a by-reference capture: ''&*$args''. This looks like a random sequences of special characters. Combined with a typehint the syntax looks a lot like a pointer: ''Foo *$args''.
   * ''params $args''. This is what C# does. This would require making ''params'' a keyword. Furthermore this doesn't have any nice way to declare typehints. In C# this is done using ''params type[] args'', but PHP doesn't have ''type[]'' hints and introducing them only here doesn't seem right.   * ''params $args''. This is what C# does. This would require making ''params'' a keyword. Furthermore this doesn't have any nice way to declare typehints. In C# this is done using ''params type[] args'', but PHP doesn't have ''type[]'' hints and introducing them only here doesn't seem right.
    
-The proposed syntax is also used by Java.+The proposed syntax is also used by Java and will be used in [[http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters|Javascript (ECMAScript Harmony proposal)]]. Go and C++ also employ a similar syntax.
  
 ===== Patch ===== ===== Patch =====
  
 Patch available in PR#421: https://github.com/php/php-src/pull/421 Patch available in PR#421: https://github.com/php/php-src/pull/421
 +
 +===== Vote =====
 +
 +The vote started on 16.09.2013 and ended on 23.09.2013. There were 36 votes in favor and one against, as such the necessary two-third majority is met and this feature is **accepted**.
 +
 +<doodle title="Should the proposed variadic-function syntax be added in PHP 5.6 (master)?" auth="nikic" voteType="single" closed="true">
 +   * Yes
 +   * No
 +</doodle>
 +
 +===== Argument unpacking =====
 +
 +The [[rfc:argument_unpacking|argument unpacking RFC]] introduces the following related syntax:
 +
 +<code php>
 +$db->query($query, ...$params);
 +</code>
rfc/variadics.1377705488.txt.gz · Last modified: 2017/09/22 13:28 (external edit)