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
Last revisionBoth sides next revision
rfc:variadics [2013/08/28 14:12] nikicrfc:variadics [2013/09/26 19:32] – Implemented nikic
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 38: Line 38:
 class MySQL implements DB { class MySQL implements DB {
     public function query($query, ...$params) {     public function query($query, ...$params) {
-        $stmt = $this->prepare($query);+        $stmt = $this->pdo->prepare($query);
         $stmt->execute($params);         $stmt->execute($params);
         return $stmt;         return $stmt;
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->prepare($query);+        $stmt = $this->pdo->prepare($query);
         foreach ($params as $i => &$param) {         foreach ($params as $i => &$param) {
             $stmt->bindParam($i + 1, $param);             $stmt->bindParam($i + 1, $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 116: Line 134:
 public function query($query, ...$params) public function query($query, ...$params)
  
-// INVALID: Chaning typehint of variadic parameter to incompatible typehint+// INVALID: Changing the typehint of variadic parameter to an incompatible typehint
 public function query($query, array ...$params) public function query($query, array ...$params)
 public function query($query, callable ...$params) public function query($query, callable ...$params)
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 144: Line 174:
 </code> </code>
  
-The functions will return ''true'' is the function/parameter is variadic, ''false'' otherwise.+The functions will return ''true'' if the function/parameter is variadic, ''false'' otherwise.
  
 ==== Summary ==== ==== Summary ====
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 160: Line 190:
   * It is no longer necessary to ''array_slice()'' the variadic arguments from ''func_get_args()''   * It is no longer necessary to ''array_slice()'' the variadic arguments from ''func_get_args()''
   * It is now possible to do variadic by-reference captures   * It is now possible to do variadic by-reference captures
 +  * 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 186: 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 203: Line 237:
 Some possible alternative syntax and why I don't like it: Some possible alternative syntax and why I don't like it:
  
-  * ''%%$args...%%''. With ref-modifier (''%%&$args...%%'') this does not show well that the individual arguments are references, not ''$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.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1