Skip to content

Dedicated syntax for variadic parameters #421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Zend/tests/variadic/adding_additional_optional_parameter.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
It's possible to add additional optional arguments with matching signature
--FILE--
<?php

interface DB {
public function query($query, string ...$params);
}

class MySQL implements DB {
public function query($query, string $extraParam = null, string ...$params) { }
}

?>
===DONE===
--EXPECT--
===DONE===
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Additional optional parameters must have a matching prototype
--FILE--
<?php

interface DB {
public function query($query, string ...$params);
}

class MySQL implements DB {
public function query($query, int $extraParam = null, string ...$params) { }
}

?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, string ...$params) in %s on line %d
57 changes: 57 additions & 0 deletions Zend/tests/variadic/basic.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
Basic variadic function
--FILE--
<?php

function test1(... $args) {
var_dump($args);
}

test1();
test1(1);
test1(1, 2, 3);

function test2($arg1, $arg2, ...$args) {
var_dump($arg1, $arg2, $args);
}

test2(1, 2);
test2(1, 2, 3);
test2(1, 2, 3, 4, 5);

?>
--EXPECT--
array(0) {
}
array(1) {
[0]=>
int(1)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
int(1)
int(2)
array(0) {
}
int(1)
int(2)
array(1) {
[0]=>
int(3)
}
int(1)
int(2)
array(3) {
[0]=>
int(3)
[1]=>
int(4)
[2]=>
int(5)
}
24 changes: 24 additions & 0 deletions Zend/tests/variadic/by_ref.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Variadic arguments with by-reference passing
--FILE--
<?php

function test(&... $args) {
$i = 0;
foreach ($args as &$arg) {
$arg = $i++;
}
}

test();
test($a);
var_dump($a);
test($b, $c, $d);
var_dump($b, $c, $d);

?>
--EXPECT--
int(0)
int(0)
int(1)
int(2)
12 changes: 12 additions & 0 deletions Zend/tests/variadic/by_ref_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
By-ref variadics enforce the reference
--FILE--
<?php

function test(&... $args) { }

test(1);

?>
--EXPECTF--
Fatal error: Only variables can be passed by reference in %s on line %d
10 changes: 10 additions & 0 deletions Zend/tests/variadic/no_default_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Variadic argument cannot have a default value
--FILE--
<?php

function test(...$args = 123) {}

?>
--EXPECTF--
Fatal error: Variadic parameter cannot have a default value in %s on line %d
16 changes: 16 additions & 0 deletions Zend/tests/variadic/non_variadic_implements_variadic_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
It's not possible to turn a variadic function into a non-variadic one
--FILE--
<?php

interface DB {
public function query($query, ...$params);
}

class MySQL implements DB {
public function query($query, $params) { }
}

?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, ...$params) in %s on line %d
10 changes: 10 additions & 0 deletions Zend/tests/variadic/only_last_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Only the last argument can be variadic
--FILE--
<?php

function test($foo, ...$bar, $baz) {}

?>
--EXPECTF--
Fatal error: Only the last parameter can be variadic in %s on line %d
49 changes: 49 additions & 0 deletions Zend/tests/variadic/optional_params.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--TEST--
Optional parameter before variadic parameter
--FILE--
<?php

function fn($reqParam, $optParam = null, ...$params) {
var_dump($reqParam, $optParam, $params);
}

fn(1);
fn(1, 2);
fn(1, 2, 3);
fn(1, 2, 3, 4);
fn(1, 2, 3, 4, 5);

?>
--EXPECT--
int(1)
NULL
array(0) {
}
int(1)
int(2)
array(0) {
}
int(1)
int(2)
array(1) {
[0]=>
int(3)
}
int(1)
int(2)
array(2) {
[0]=>
int(3)
[1]=>
int(4)
}
int(1)
int(2)
array(3) {
[0]=>
int(3)
[1]=>
int(4)
[2]=>
int(5)
}
20 changes: 20 additions & 0 deletions Zend/tests/variadic/removing_parameter_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
It's not possible to remove required parameter before a variadic parameter
--FILE--
<?php

/* Theoretically this should be valid because it weakens the constraint, but
* PHP does not allow this (for non-variadics), so I'm not allowing it here, too,
* to stay consistent. */

interface DB {
public function query($query, ...$params);
}

class MySQL implements DB {
public function query(...$params) { }
}

?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, ...$params) in %s on line %d
36 changes: 36 additions & 0 deletions Zend/tests/variadic/typehint_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
Variadic arguments enforce typehints
--FILE--
<?php

function test(array... $args) {
var_dump($args);
}

test();
test([0], [1], [2]);
test([0], [1], 2);

?>
--EXPECTF--
array(0) {
}
array(3) {
[0]=>
array(1) {
[0]=>
int(0)
}
[1]=>
array(1) {
[0]=>
int(1)
}
[2]=>
array(1) {
[0]=>
int(2)
}
}

Catchable fatal error: Argument 3 passed to test() must be of the type array, integer given, called in %s on line %d
33 changes: 33 additions & 0 deletions Zend/tests/variadic/typehint_suppressed_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Error suppression for typehints on variadic arguments works
--FILE--
<?php

function test(array... $args) {
var_dump($args);
}

set_error_handler(function($errno, $errstr) {
var_dump($errstr);
return true;
});

test([0], [1], 2);

?>
--EXPECTF--
string(%d) "Argument 3 passed to test() must be of the type array, integer given, called in %s on line %d and defined"
array(3) {
[0]=>
array(1) {
[0]=>
int(0)
}
[1]=>
array(1) {
[0]=>
int(1)
}
[2]=>
int(2)
}
16 changes: 16 additions & 0 deletions Zend/tests/variadic/variadic_changed_byref_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Variadic arguments must have compatible passing modes
--FILE--
<?php

interface DB {
public function query($query, &...$params);
}

class MySQL implements DB {
public function query($query, ...$params) { }
}

?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, &...$params) in %s on line %d
16 changes: 16 additions & 0 deletions Zend/tests/variadic/variadic_changed_typehint_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Typehints for variadic arguments have to be compatible
--FILE--
<?php

interface DB {
public function query($query, string ...$params);
}

class MySQL implements DB {
public function query($query, int ...$params) { }
}

?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, string ...$params) in %s on line %d
17 changes: 17 additions & 0 deletions Zend/tests/variadic/variadic_implements_non_variadic.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
A non-variadic function can be turned into a variadic one
--FILE--
<?php

interface DB {
public function query($query);
}

class MySQL implements DB {
public function query($query, ...$params) { }
}

?>
===DONE===
--EXPECT--
===DONE===
10 changes: 3 additions & 7 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -2090,16 +2090,12 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
} else {
internal_function->required_num_args = info->required_num_args;
}
if (info->pass_rest_by_reference) {
if (info->pass_rest_by_reference == ZEND_SEND_PREFER_REF) {
internal_function->fn_flags |= ZEND_ACC_PASS_REST_PREFER_REF;
} else {
internal_function->fn_flags |= ZEND_ACC_PASS_REST_BY_REFERENCE;
}
}
if (info->return_reference) {
internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
}
if (ptr->arg_info[ptr->num_args].is_variadic) {
internal_function->fn_flags |= ZEND_ACC_VARIADIC;
}
} else {
internal_function->arg_info = NULL;
internal_function->num_args = 0;
Expand Down
Loading