[RFC] Syntax for variadic functions

php.internals

Nikita Popov

13 years ago
Hi internals! I'd like to propose an RFC, which adds dedicated syntax for variadic functions: https://wiki.php.net/rfc/variadics Basically this allows declaring variadics directly in the function signature, rather than fetching the arguments using func_get_args(). Example: public function query($query, ...$params) { /* ... */ } What are your thoughts on this? Thanks, Nikita

Lazare Inepologlou

13 years ago
2013/8/28 Nikita Popov <nikita.ppv@gmail.com>
> Hi internals! > > I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > > https://wiki.php.net/rfc/variadics > > Basically this allows declaring variadics directly in the function > signature, rather than fetching the arguments using func_get_args(). > Example: > > public function query($query, ...$params) { /* ... */ } > > What are your thoughts on this? > >
+1, primarily because it makes the code self-documented. However, I would like to hilight one shortcoming of variadic functions (both with the old and with the proposed syntax): There is no way to call a variadic function unless all the arguments are hard-coded. I am extenting the example of the RFC: class MySQL implements DB { public function query($query, ...$params) { // ... } public function query_and_log($query, ...$params) { // this will not work: $result = $this->query( $query, $params ); log( $query ); return $result; } } Not only this does not work, but there is no way to make it work without modifying the original function. Would it be possible to extend the RFC with new syntax that could cover cases like that as well? Maybe something like that: $result = $this->query( $query, ...$params ); Other than that, the RFC is very welcome. Lazare INEPOLOGLOU Ingénieur Logiciel

Nikita Popov

13 years ago
On Wed, Aug 28, 2013 at 6:18 PM, Lazare Inepologlou <linepogl@gmail.com>wrote:
> Not only this does not work, but there is no way to make it work without > modifying the original function. Would it be possible to extend the RFC > with new syntax that could cover cases like that as well? Maybe something > like that: > > $result = $this->query( $query, ...$params ); >
I will implement this, but in a separate RFC :) [Later today or tomorrow] Nikita

Ivan Enderlin @ Hoa

13 years ago
On 28/08/13 17:47, Nikita Popov wrote:
> Hi internals!
Hi Nikita :-),
> I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > > https://wiki.php.net/rfc/variadics > > Basically this allows declaring variadics directly in the function > signature, rather than fetching the arguments using func_get_args(). > Example: > > public function query($query, ...$params) { /* ... */ } > > What are your thoughts on this?
Huge +1! So if we call query('foo'), $params is set to an empty array, right? Could it be possible to change this behavior? Would it be interesting? For example: public function query($query, ...$params = null). Cheers.
-- Ivan Enderlin Developer of Hoa http://hoa-project.net/ PhD. student at DISC/Femto-ST (Vesontio) and INRIA (Cassis) http://disc.univ-fcomte.fr/ and http://www.inria.fr/ Member of HTML and WebApps Working Group of W3C http://w3.org/

Matthew Leverton

13 years ago
On Wed, Aug 28, 2013 at 10:47 AM, Nikita Popov <nikita.ppv@gmail.com> wrote:
> Hi internals! > > I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > ... > > What are your thoughts on this? >
I think it's great way to clean things up and add some subtle new functionality, particularly with Lazare's follow-up proposal about expanding an indexed array into arguments. Would any functions get deprecated as a result of this? e.g., func_get_args() I assume it's a syntax error to do function fn(...$foo, $bar) or function fn(...$foo, ...$bar) I assume that function fn($a, $b = null, ...$c) is possible, and the only way to populate $c is to call fn with three or more parameters.
-- Matthew Leverton

Marc Bennewitz

13 years ago
Am 28.08.2013 21:27, schrieb Matthew Leverton:
> On Wed, Aug 28, 2013 at 10:47 AM, Nikita Popov <nikita.ppv@gmail.com> wrote: >> <snip> > > Would any functions get deprecated as a result of this? e.g., func_get_args() > > <snip> >
It's not a good idea to deprecate the function func_get_args/func_num_args() because it is used in user land code to detect if a function was called with a specific argument like the following: function (&$argByRef = null) { if (func_num_args() > 1) { // do expensive stuff to set $argByRef $argByRef = true; } return false; }

Nikita Popov

13 years ago
On Wed, Aug 28, 2013 at 9:27 PM, Matthew Leverton <leverton@gmail.com>wrote:
> Would any functions get deprecated as a result of this? e.g., > func_get_args() >
Nope, func_get_args() etc stay. This is now mentioned in https://wiki.php.net/rfc/variadics#userland.
> I assume it's a syntax error to do function fn(...$foo, $bar) or > function fn(...$foo, ...$bar) >
Correct. This is now mentioned in https://wiki.php.net/rfc/variadics#syntactic_restrictions.
> I assume that function fn($a, $b = null, ...$c) is possible, and the > only way to populate $c is to call fn with three or more parameters. >
That's also correct :) Nikita

Damian Wadley

13 years ago
How about having the ellipsis _after_ the variable? That then coincides with phpDocumentor's recommended syntax of "$c,..." and it keeps any typehint or & with the variable name ("array &$arr..." versus "array &...$arr") and, honestly, I think that reads more easily. On Wed, Aug 28, 2013 at 1:15 PM, Nikita Popov <nikita.ppv@gmail.com> wrote:

Nikita Popov

13 years ago
On Wed, Aug 28, 2013 at 11:01 PM, Damian Wadley <php@requinix.net> wrote:
> How about having the ellipsis _after_ the variable? That then coincides > with phpDocumentor's recommended syntax of "$c,..." >
That syntax has it neither before nor after, because there is no parameter name. and it keeps any typehint or & with the variable name ("array &$arr..."
> versus "array &...$arr") and, honestly, I think that reads more easily. >
Please see the https://wiki.php.net/rfc/variadics#choice_of_syntax section of the RFC. Quoting: "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." Thanks, Nikita

Stas Malyshev

13 years ago
Hi! I like the idea, the concept of capturing "rest of args" is pretty common. But couldn't we in addition have func_get_args() be able to receive an int argument that would produce "the rest" in an easier way for those that prefer func_ger_args()? I wonder if this makes harder to implement named argument in the future - which I think we still need to be looking at - but so far doesn't look like it presents any additional problem compared to func_get_args(). For prototype checks, this: public function query($query, ...$params); public function query($query, $param = null, ...$params); Should be compatible. Same with: public function query($query, ...$params); public function query($query); functions should be able to ignore some arguments, especially ones that are optional anyway. I also think this: public function query($query, ...$params) public function query(...$params) should be legal too. I think it should also be explicitly specified what $params is if there is no arguments - null? false? array()? I'd probably prefer array as it makes it easy to do something like: public __construct(...$params) { foreach($params as $k => $v) { $this->$k = $v; } } but in any way it should be specified. I didn't look at the implementation yet, so I'll add comments on that later.
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/ (408)454-6900 ext. 227

Levi Morrison

13 years ago
> > functions should be able to ignore some arguments, especially ones that > are optional anyway.
This is not the current behavior, so why should we change it? See: 1 <?php 2 3 interface TestInterface { 4 function query($params = null); 5 } 6 7 class TestImplementation implements TestInterface { 8 function query() { 9 10 } 11 } Fatal error: Declaration of TestImplementation::query() must be compatible with that of TestInterface::query() in /Users/levijm/Projects/HighlightPHP/tmp.php on line 7

Stas Malyshev

13 years ago
Hi!
> functions should be able to ignore some arguments, especially ones that > are optional anyway. > > > This is not the current behavior, so why should we change it? See:
Because it makes no sense?
-- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/ (408)454-6900 ext. 227

Nikita Popov

13 years ago
On Thu, Aug 29, 2013 at 12:09 AM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:
> Hi! > > I like the idea, the concept of capturing "rest of args" is pretty > common. But couldn't we in addition have func_get_args() be able to > receive an int argument that would produce "the rest" in an easier way > for those that prefer func_ger_args()? >
I would do that if this RFC doesn't pass, but I don't see much point doing both things (syntax + extra arg). Are there any particular scenarios where using func_get_args() would be preferable?
> For prototype checks, this: > > public function query($query, ...$params); > public function query($query, $param = null, ...$params); > > Should be compatible.
It already is. Only requirement is that the typehint/by-ref-mode of $param=null is compatible with the typehint/by-ref-mode of ...$params :)
> Same with: > > public function query($query, ...$params); > public function query($query); > > functions should be able to ignore some arguments, especially ones that > are optional anyway. I also think this: > > public function query($query, ...$params) > public function query(...$params) > > should be legal too. >
I would like to stay consistent with the normal PHP behavior here. PHP currently doesn't allow leaving off (required or optional) parameters. I created a separate thread regarding that issue: http://markmail.org/message/ejgmqjnjnbmfnuzv If we decide to allow having less parameters there, then I'll follow suit here as well.
> I think it should also be explicitly specified what $params is if there > is no arguments - null? false? array()? I'd probably prefer array as it > makes it easy to do something like: > > public __construct(...$params) { > foreach($params as $k => $v) { $this->$k = $v; } > } > > but in any way it should be specified. >
Now specified in https://wiki.php.net/rfc/variadics#population_of_variadic_parameter: The default is an empty array. Thanks for the comments, Nikita

Zeev Suraski

12 years ago
> -----Original Message----- > From: Nikita Popov [mailto:nikita.ppv@gmail.com] > Sent: Thursday, August 29, 2013 3:03 PM > To: Stas Malyshev > Cc: PHP internals > Subject: Re: [PHP-DEV] [RFC] Syntax for variadic functions > > On Thu, Aug 29, 2013 at 12:09 AM, Stas Malyshev > <smalyshev@sugarcrm.com>wrote: > > > Hi! > > > > I like the idea, the concept of capturing "rest of args" is pretty > > common. But couldn't we in addition have func_get_args() be able to > > receive an int argument that would produce "the rest" in an easier way > > for those that prefer func_ger_args()? > > > > I would do that if this RFC doesn't pass, but I don't see much point
doing
> both things (syntax + extra arg). Are there any particular scenarios
where
> using func_get_args() would be preferable?
Admittedly I'm (very) late to the game, but admittedly #2 - I actually just noticed this thread as it went up for a vote. Personally I find Stas's direction preferable to introducing new semantics - mainly because I think that with every new piece of syntax we make the language a tad bit more complex no matter what. Conversely, adding an optional argument to func_get_args() sticks with the same spirit we've had for years regarding variadic functions, and arguably is more versatile. Assuming we implement a [, start[, end]] syntax support, then you can more granularly split exactly the offsets you want - in case you don't want all of them in one array (which would require a call to array_slice() using the new syntax). Before you jump and say it's not such a common case - I agree - I said arguably :) Zeev

Zeev Suraski

12 years ago
> -----Original Message----- > From: Zeev Suraski [mailto:zeev@zend.com] > Sent: Monday, September 16, 2013 11:52 PM > To: 'Nikita Popov'; 'Stas Malyshev' > Cc: 'PHP internals' > Subject: RE: [PHP-DEV] [RFC] Syntax for variadic functions > > > -----Original Message----- > > From: Nikita Popov [mailto:nikita.ppv@gmail.com] > > Sent: Thursday, August 29, 2013 3:03 PM > > To: Stas Malyshev > > Cc: PHP internals > > Subject: Re: [PHP-DEV] [RFC] Syntax for variadic functions > > > > On Thu, Aug 29, 2013 at 12:09 AM, Stas Malyshev > > <smalyshev@sugarcrm.com>wrote: > > > > > Hi! > > > > > > I like the idea, the concept of capturing "rest of args" is pretty > > > common. But couldn't we in addition have func_get_args() be able to > > > receive an int argument that would produce "the rest" in an easier > > > way for those that prefer func_ger_args()? > > > > > > > I would do that if this RFC doesn't pass, but I don't see much point > > doing both things (syntax + extra arg). Are there any particular > > scenarios where using func_get_args() would be preferable? > > Admittedly I'm (very) late to the game, but admittedly #2 - I actually
just
> noticed this thread as it went up for a vote. > Personally I find Stas's direction preferable to introducing new
semantics -
> mainly because I think that with every new piece of syntax we make the > language a tad bit more complex no matter what. > Conversely, adding an optional argument to func_get_args() sticks with
the
> same spirit we've had for years regarding variadic functions, and
arguably is
> more versatile. Assuming we implement a [, start[, end]] syntax
support,
> then you can more granularly split exactly the offsets you want - in
case you
> don't want all of them in one array (which would require a call to > array_slice() using the new syntax). Before you jump and say it's not
such a
> common case - I agree - I said arguably :)
After thinking about it some more I see more value in the 2nd feature of this RFC - the ability to do pass by reference on variable argument lists - than I initially realized, so I'm actually in favor of the RFC. I'm still in favor of func_get_args() being updated with start/end optional parameters though. Zeev

Patrick ALLAERT

13 years ago
2013/8/28 Nikita Popov <nikita.ppv@gmail.com>:
> Hi internals! > > I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > > https://wiki.php.net/rfc/variadics > > Basically this allows declaring variadics directly in the function > signature, rather than fetching the arguments using func_get_args(). > Example: > > public function query($query, ...$params) { /* ... */ } > > What are your thoughts on this? > > Thanks, > Nikita
Using the current variadic functions makes it possible to use 0 or N arguments, e.g.: function sum() { return array_sum(func_get_args()); } echo sum(10, 5); // echoes 15 echo sum(); // echoes 0 I see nowhere in the RFC whether: function sum(...$params) { /* */ } Requires at minimum one argument or none. I have the _feeling_ that you imply it's minimum one which I would consider a bit inconsistent with the current "implementation". Can you please clarify this Nikita? Thanks

Lester Caine

13 years ago
Nikita Popov wrote:
> I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > > https://wiki.php.net/rfc/variadics
I can remember in PHP4 days, passing parameters to the database as a string of variables was the norm. Then arrays came along and it was preferable to pass the query followed by an array of values. We could take the array and validate the data in a function, adding any missing values needed before processing the SQL. Going back to the cumbersum method of working just seems wrong? Surely we should be promoting a tidier method of working?
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

Bryan C. Geraghty

13 years ago
Lester's position seems unclear but I'll weigh-in. Having strict interfaces and arguments means that the developer does not have to parse and validate each parameter that is arbitrarily passed in. If anything, I would prefer to see func_get_args() removed entirely. Now, I know that won't happen but I don't think extending the associated functionality to be more vague is a good choice. -----Original Message----- From: Lester Caine [mailto:lester@lsces.co.uk] Sent: Thursday, August 29, 2013 7:52 AM To: PHP internals Subject: Re: [PHP-DEV] [RFC] Syntax for variadic functions Nikita Popov wrote:
> I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > > https://wiki.php.net/rfc/variadics
I can remember in PHP4 days, passing parameters to the database as a string of variables was the norm. Then arrays came along and it was preferable to pass the query followed by an array of values. We could take the array and validate the data in a function, adding any missing values needed before processing the SQL. Going back to the cumbersum method of working just seems wrong? Surely we should be promoting a tidier method of working?
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php

Jonathan Bond-Caron

13 years ago
On Wed Aug 28 11:47 AM, Nikita Popov wrote:
> > https://wiki.php.net/rfc/variadics
Interesting idea, expanding on: function log($message, ...$options) {} It would seem convenient to allow ...$options to be passed as a key-value array of arguments as well: function logA($message, ...$options[]) { echo count($options); } logA("foo"); // 0 logA("foo", 1, 2); // 2 logA("foo", array(1,2,3)); // 3 The difference here is that variadic options is declared as an optional array, it would not support a 'typehint' forcing all arguments to be of the same type. It could be a way to support ~ named parameters // requires at least 1 argument named as 'level' function logB($message, ...$options['level']) { echo $options['level'] .' '. count($options); } logB("foo"); // fails: 'level' argument missing logB("foo", 'notice'); //notice 1 logB("foo", ['level' => 'notice']); // notice 1 logB("foo", 'notice', 'extra'); // notice 2 logB("foo", ['level' => 'notice'], 'extra'); // notice 2 // requires min 2 arguments function logC($message, ...$options['level','priority']) { echo 'level:'. $options['level']; echo 'priority:'. $options['priority']; } logC("foo", "notice", 4); logC("foo", ['level' => 'notice', 'priority' => 4]); That would remove the need for a "splat" or "scatter" operator. The declaration "...$options[]" would mean, I accept an array of arguments followed by extra arguments

Sebastian Krebs

13 years ago
2013/8/30 jbondc@openmv.com <jbondc@openmv.com>
> On Wed Aug 28 11:47 AM, Nikita Popov wrote: > > > > https://wiki.php.net/rfc/variadics > > Interesting idea, expanding on: > > function log($message, ...$options) {} > > It would seem convenient to allow ...$options to be passed as a key-value > array of arguments as well: > function logA($message, ...$options[]) { echo count($options); } > > logA("foo"); // 0 > logA("foo", 1, 2); // 2 > logA("foo", array(1,2,3)); // 3 > > The difference here is that variadic options is declared as an optional > array, it would not support a 'typehint' forcing all arguments to be of the > same type. > It could be a way to support ~ named parameters > > // requires at least 1 argument named as 'level' > function logB($message, ...$options['level']) { > echo $options['level'] .' '. count($options); > } > > logB("foo"); // fails: 'level' argument > missing > logB("foo", 'notice'); //notice 1 > logB("foo", ['level' => 'notice']); // notice 1 > logB("foo", 'notice', 'extra'); // notice 2 > logB("foo", ['level' => 'notice'], 'extra'); // notice 2 > > // requires min 2 arguments > function logC($message, ...$options['level','priority']) { > echo 'level:'. $options['level']; > echo 'priority:'. $options['priority']; > } > logC("foo", "notice", 4); > logC("foo", ['level' => 'notice', 'priority' => 4]); > > That would remove the need for a "splat" or "scatter" operator. The > declaration "...$options[]" would mean, I accept an array of arguments > followed by extra arguments >
I'd recommend to use an object, or separate parameters instead. Thats not a use-case for argument-lists. Regards Sebastian
> > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- github.com/KingCrunch

Nikita Popov

12 years ago
On Wed, Aug 28, 2013 at 5:47 PM, Nikita Popov <nikita.ppv@gmail.com> wrote:
> Hi internals! > > I'd like to propose an RFC, which adds dedicated syntax for variadic > functions: > > https://wiki.php.net/rfc/variadics > > Basically this allows declaring variadics directly in the function > signature, rather than fetching the arguments using func_get_args(). > Example: > > public function query($query, ...$params) { /* ... */ } > > What are your thoughts on this? >
I'd like to go forward with voting on this. Are there any issues that still need to be resolved? Nikita

Sara Golemon

12 years ago
> > > I'd like to go forward with voting on this. Are there any issues that still > need to be resolved? > > Assuming the RFC as-is represents the current state, I'm +1 on all of it.
I'm not a fan of some of the proposed alterations which would translate arrays (a la call_user_func_array()). To clarify, the following output is what I'd expect: function f(...$args) { echo count($args); } f(1,2,3); // 3 f([1,2,3]); // 1 Not "3" in both cases. -Sara

Nikita Popov

12 years ago
On Mon, Sep 16, 2013 at 9:02 PM, Sara Golemon <pollita@php.net> wrote:
> >> I'd like to go forward with voting on this. Are there any issues that >> still >> need to be resolved? >> >> Assuming the RFC as-is represents the current state, I'm +1 on all of it. > > I'm not a fan of some of the proposed alterations which would translate > arrays (a la call_user_func_array()). To clarify, the following output is > what I'd expect: > function f(...$args) { > echo count($args); > } > f(1,2,3); // 3 > f([1,2,3]); // 1 > > Not "3" in both cases. >
Yes, that's the output you'll get. If it weren't the case it would be impossible to define a function accepting multiple array arguments like f([1, 2, 3], [4, 5, 6], [7, 8, 9]). Nikita

Sara Golemon

12 years ago
> Assuming the RFC as-is represents the current state, I'm +1 on all of it. >> >> I'm not a fan of some of the proposed alterations which would translate >> arrays (a la call_user_func_array()). To clarify, the following output is >> what I'd expect: >> function f(...$args) { >> echo count($args); >> } >> f(1,2,3); // 3 >> f([1,2,3]); // 1 >> >> Not "3" in both cases. >> > > Yes, that's the output you'll get. If it weren't the case it would be > impossible to define a function accepting multiple array arguments like > f([1, 2, 3], [4, 5, 6], [7, 8, 9]). > > Right, that was exactly the ambiguity I was unfond of. Glad that was as I
hoped. Voted +1.