245

While I am installing Magento 2 on my Server, I got an error. After investigating the code and found that there are three dots (...), which is producing the error. I included the code I found below:

return new $type(...array_values($args));

What is this operator called, and what is its purpose?

6

9 Answers 9

333

This is literally called the ... operator in PHP, but is known as the splat operator from other languages. From a 2014 LornaJane blog post on the feature:

This feature allows you to capture a variable number of arguments to a function, combined with "normal" arguments passed in if you like. It's easiest to see with an example:

function concatenate($transform, ...$strings) {
    $string = '';
    foreach($strings as $piece) {
       $string .= $piece;
    }
    return($transform($string));  
 }

echo concatenate("strtoupper", "I'd ", "like ", 4 + 2, " apples");

(This would print I'D LIKE 6 APPLES)

The parameters list in the function declaration has the ... operator in it, and it basically means " ... and everything else should go into $strings". You can pass 2 or more arguments into this function and the second and subsequent ones will be added to the $strings array, ready to be used.

9
  • 3
    Thanks :), why should I use SPLAT operator, instead of this I can pass all those strings in an array as the second argument??? Commented Jun 4, 2018 at 16:54
  • 3
    @bikash.bilz I'll speak for the answerer: I think it's just syntactic sugar. The splat operator saves you from surrounding the arguments with [ and ]. It's not much of a benefit but I think it looks nice. Commented Jun 21, 2018 at 4:43
  • 50
    You can type-hint the variadic parameters too. So on PHP 7.2, you can define function myFunc($foo, string ...$bar). Then $bar gives your function an array of strings and nothing else, guaranteed at run-time. You cannot do that with a single array parameter.
    – Jason
    Commented Aug 16, 2018 at 15:44
  • 7
    This is more than just syntax sugar because it allows an array in contexts that would otherwise require a fixed number of strings. Using a fixed number of strings requires you to re-factor your source code every time the number of strings might change.
    – dreftymac
    Commented Jul 30, 2019 at 3:08
  • 6
    An easy example is a function signature used to query a database. function get_data($fname,$lname,$age) will have to change if you want fields other than those three function get_data(...$fields) does not have to change, you need only specify the fields you want in $fields. @heykatieben
    – dreftymac
    Commented Sep 10, 2019 at 20:58
118

There are THREE uses for the ellipsis (...) PHP token.

Think of the first two as packing and unpacking an array. These purposes apply to function parameters (function definition) and arguments (function execution).

And the third, first class callable syntax, introduced in PHP 8.1.0, has another usage—to create an anonymous function from an existing function. In this case the operator is used instead of function arguments.


Pack

When defining a function, if you need a dynamic number of variables provided to the function (i.e., you don't know how many arguments will be provided to that function when called in your code), prefix the ellipsis (...) token to a variable name—e.g., ...$numbers—to capture all (remaining) arguments provided to that function into an array assigned to the named variable—in this case $numbers—that is accessible inside the function block. The number of arguments captured by prefixing ellipsis (...) can be zero or more.

For example:

// function definition
function sum (...$numbers) { // use ellipsis token when defining function
    $acc = 0;
    foreach ($numbers as $nn) {
        $acc += $nn;
    }
    return $acc;
}

// call the function
echo sum(1, 2, 3, 4); // provide any number of arguments

> 10

// and again...
echo sum(1, 2, 3, 4, 5);

> 15

// and again...
echo sum();

> 0

When packing is used while writing a new function, prefixing ellipsis (...) to a variable name captures all remaining arguments, i.e., you can still have any number—zero or more—of initial, fixed (positional) arguments:

function sum ($first, $second, ...$remaining_numbers) {
    $acc = $first + $second;
    foreach ($remaining_numbers as $nn) {
        $acc += $nn;
    }
    return $acc;
}

// call the function
echo sum(1, 2); // provide at least two arguments

> 3

// and again...
echo sum(1, 2, 3, 4); // first two are assigned to fixed arguments, the rest get "packed"

> 10

...the prefixed ellipsis variable captures all the rest. For this reason it must be the final function argument.


Unpack

Alternatively, when calling a function, if the arguments you provide to that function are previously combined into an array, use an ellipsis (...) token-prefixed variable "inline" to convert that array variable into individual arguments provided to the function. When any number of function arguments are replaced with an ellipsis-prefixed variable, each array element is assigned to the respective function argument variable named in the function definition.

For example:

function add ($aa, $bb, $cc) {
    return $aa + $bb + $cc;
}

$arr = [1, 2, 3];
echo add(...$arr); // use ellipsis token when calling function

> 6

$first = 1;
$arr = [2, 3];
echo add($first, ...$arr); // used with positional arguments

> 6

$first = 1;
$arr = [2, 3, 4, 5]; // array can be "oversized"
echo add($first, ...$arr); // remaining elements are ignored

> 6

Unpacking is particularly useful when using array functions to manipulate arrays or variables.

For example, unpacking the result of array_slice:

function echoTwo ($one, $two) {
    echo "$one\n$two";
}

$steaks = array('ribeye', 'kc strip', 't-bone', 'sirloin', 'chuck');

// array_slice returns an array, but ellipsis unpacks it into function arguments
echoTwo(...array_slice($steaks, -2)); // return last two elements in array

> sirloin
> chuck

First class callable

As of PHP 8.1.0, when an ellipsis (...) token is applied in place of the function arguments, e.g. strlen(...), it's a First class callable syntax, which means it creates an anonymous function from a callable, in other words, from an existing function.

$sl = strlen(...); // create an anonymous function from an internal function
echo $sl('fun stuff'); // execute it

> 9

// a user-defined function
function test($hey, $there) {
  echo $hey . $there;
}

$ya = test(...); // create an anonymous function
$ya('oopsy', 'daisy'); // execute it

> oopsydaisy
1
  • Unpack is super uselfull for Doctrine's OrX function
    – Erdal G.
    Commented Jul 17, 2020 at 11:19
29

Every answer refers to the same blog post, besides them, here is the official documentation about variable-length argument lists:

http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list

In PHP 5.6 and later, argument lists may include the ... token to denote that the function accepts a variable number of arguments. The arguments will be passed into the given variable as an array

It seems "splat" operator is not an official name, still it's cute!

19

In PHP 8.1, this syntax "(...)" is used as a new way to create callables.

Before PHP 8.1:

$callable = [$this, 'myMethod'];

After PHP 8.1:

$callable = $this->myMethod(...);

Source: https://wiki.php.net/rfc/first_class_callable_syntax

4
  • 10
    This is not the answer to the author's original question, but it may be relevant to anyone who googles 'php 3 dots'
    – michal3377
    Commented Oct 24, 2021 at 21:43
  • Now, it's in the doc: php.net/manual/en/functions.first_class_callable_syntax.php
    – ssi-anik
    Commented Sep 29, 2022 at 1:23
  • And, if want to check the usage: github.com/symfony/console/blob/…
    – ssi-anik
    Commented Sep 29, 2022 at 1:25
  • @michal3377 the author's original question was what the ... operator is, and what is its purpose. While the author did not encounter it in this context originally, this is the same operator with the same name and an additional purpose so techincally the author did also ask about this even if they didn't realise at the time
    – apokryfos
    Commented Jul 27, 2023 at 4:37
19

Meaning is that it decomposes an associative array to a list. So you do not need to type N parameters to call a method, just one. If method allows a decomposed parameter and if parameters are of the same type.

For me, the most important thing about splat operator is that it can help to typehint array parameters:

$items = [
    new Item(), 
    new Item()
];

$collection = new ItemCollection();
$collection->add(...$items); // !

// what works as well:
// $collection->add(new Item());
// $collection->add(new Item(), new Item(), new Item()); // :(

class Item  {};
 
class ItemCollection {
    
    /**
     * @var Item[]
     */
    protected $items = [];
    
    public function add(Item ...$items)
    {
        foreach ($items as &$item) {
            $this->items[] = $item;
        }
    }
} 

it saves some effort on type control, especially while working with huge collections or very object-oriented.

Important to notice is that ...$array do decompose an array despite the type of its items, so you can go the ugly way also:

function test(string $a, int $i) {
    echo sprintf('%s way as well', $a);
    
    if ($i === 1) {
        echo('!');
    }
}

$params = [
    (string) 'Ugly',
    (int) 1
];

test(...$params);

// Output:
// Ugly way as well!

But please don't.


PHP 8 update - named arguments

Since PHP 8 you can now decompose associative arrays, it is, arrays that have keys for them values. If you use it in function that has arguments named the same, PHP will transfer values to proper variables:

$arr = [
  'pi' => 3.14,
  'r' => 4,
];

function circ($r, $pi) {
    return 2*$pi*$r;
}

// so that call
circ(...$arr);

// will be effectively a call of
circ(pi: 3.14, r: 4);

and you can slightly less bother about order of parameters.


PHP 8.1 update - new syntax for creating callable

Despite usage with arrays, ... earned a whole new, very useful functionality that help creating callable from any context:

$f = strtoupper(...); // creating a callable
echo $f('fo');

class test {
    public function func($a) {
        echo $a . PHP_EOL;
    }
}

$f = (new test)
         ->func(...); // creating a callable

$f('x');
4
  • It's not that ugly. Like with Doctrine's OrX functions that needs a list, but you need to passe an array (because you don't know how many elements you will pass). I find this way better than using call_user_func_array
    – Erdal G.
    Commented Jul 17, 2020 at 11:18
  • @ErdalG. yet this is an array of one type conditional objects I assume?
    – yergo
    Commented Nov 22, 2020 at 14:15
  • Well honestly I don't remember the example I had in head 3 years before haha (I still should have written it). It must have been some artbitrary array of generated expressions. For the array of unique conditions you can obviously replace with with ->in() or similar methods
    – Erdal G.
    Commented Nov 22, 2020 at 14:45
  • echo sprintf() is an antipattern. Whenever you think your script needs it, don't use it, just type printf(). Commented Jun 29, 2022 at 1:21
17

In PHP 7.4 the ellipsis is also the Spread operator:

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

Source: https://wiki.php.net/rfc/spread_operator_for_array

0
6

To use this feature, just warn PHP that it needs to unpack the array into variables using the ... operator. See here for more details, a simple example could look like this:

$email[] = "Hi there";
$email[] = "Thanks for registering, hope you like it";

mail("[email protected]", ...$email);
0
4

This is the so called "splat" operator. Basically that thing translates to "any number of arguments"; introduced with PHP 5.6

See here for further details.

1

It seems no one has mentioned it, so here to stay[It will also help Google (& Other SEs) guide devs who asking for Rest Parameters in PHP]:

As indicated here its called Rest Parameters on JS & I prefer this meaningful naming over that splat thing!

In PHP, The functionality provided by ...args is called Variadic functions which's introduced on PHP5.6. Same functionality was used to be implemented using func_get_args().

In order to use it properly, you should use rest parameters syntax, anywhere it helps reducing boilerplate code.

1
  • 1
    This doesn't provide anything useful beyond the existing answers.
    – TylerH
    Commented Feb 23, 2022 at 15:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.