Both sides previous revisionPrevious revisionNext revision | Previous revision |
rfc:variadics [2013/08/28 19:57] – nikic | rfc:variadics [2017/09/22 13:28] (current) – external edit 127.0.0.1 |
---|
* 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 ===== |
| |
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 ==== |
<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) { |
| |
<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 ==== |
* ''%%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: |
==== Userland ==== | ==== Userland ==== |
| |
This change does not break backwards comparability for userland code. | 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. | In particular, this RFC does not propose to deprecate or remove the ''func_get_args()'' family of functions, at least not any time soon. |
| |
* ''%%$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 and will be used in [[http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters|Javascript (ECMAScript Harmony proposal)]]. | 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 ===== | ===== Argument unpacking ===== |
| |
A related syntactical element is the "splat" or "scatter" operator: | The [[rfc:argument_unpacking|argument unpacking RFC]] introduces the following related syntax: |
| |
<code php> | <code php> |
$db->query($query, ...$params); | $db->query($query, ...$params); |
</code> | </code> |
| |
This operator would unpack an array into an argument list (similarly to ''call_user_func_array''). It is not part of this RFC, but I plan to implement this in a separate proposal. | |