How to make PHP understand *either* an array or the splat operator (3 dots ...) for function parameters?
Asked Answered
W

2

6

I have this code:

function test(...$strings)
{
    // ...
}

It allows me to call test() like this:

test('a', 'series of', 'strings go here');

Which works. However, I often would like to do:

test([ 'a', 'series of', 'strings go here' ]);

Or:

test($an_array_of_strings);

In fact, I was so sure that this worked that I was shocked and confused when I started getting errors about "Array to string conversion".

I mean, the "..." syntax is a special language construct specifically to turn a variable number of arguments to a function into an array! I don't even understand why it would not automatically understand this very common/useful practice.

Since it (apparently) doesn't, is there some way to accomplish this without having to use two separate functions? I don't want a separate:

function test_array($strings = [])
{
    // ...
}
Werner answered 10/6, 2019 at 4:24 Comment(2)
show us inside of test function. what are you trying to do?Unseasonable
You can use the ... operator to splat the input too - test(...$an_array_of_strings) or test(...[ 'a', 'series of', 'strings go here' ]).Case
U
3

It has different results in the function.

1) If you pass multiple strings to the function, it will get an array of strings like so:

test('a', 'series of', 'strings go here');

//vardump result
array (size=3)
  0 => string 'a' (length=1)
  1 => string 'series of' (length=9)
  2 => string 'strings go here' (length=15)

2) If you pass an array to function it will get an array of arrays. The splat operator will add a first entry that you pass to function to the first index of an array, the second parameter will add into the second index and so on. so no matter what you pass to the function (array or string) it will go to index zero. but the problem is if you pass array it will generate an array of arrays in the first index of the array:

test([ 'a', 'series of', 'strings go here' ]);

//vardump result
array (size=1)
  0 => 
    array (size=3)
      0 => string 'a' (length=1)
      1 => string 'series of' (length=9)
      2 => string 'strings go here' (length=15)

Conclusion:

you can solve this with one of these two ways:

1) put 3 dots before you pass the array to the function:

test(...[ 'a', 'series of', 'strings go here' ]);

2) Another way of doing this is by adding a function named is_multi_array() to check if the variable that passed to the function is multi-dimensional. After that you can simply get the first element of the array and put it in strings variable:

function is_multi_array( $arr ) {
    rsort( $arr );
    return (isset( $arr[0] ) && is_array( $arr[0] ));
}

function test(...$strings)
{
   if(is_multi_array($strings)){
       $strings = $strings[0];
   }

   //do the rest
}

This way you can use the function in both ways that you like:

test('a', 'series of', 'strings go here');
test([ 'a', 'series of', 'strings go here' ]);
Unseasonable answered 10/6, 2019 at 4:38 Comment(0)
D
7

Same thing in reverse:

test(...$an_array_of_strings);

If you want to make it automatic (so that you don't have to use ... to splat the array onto the arguments), you would need to test manually if $strings has only a single element, which is an array; then you unsplat it manually inside the function if so. This loses you the ability to pass a single array as a single argument, and I would not recommend it. I.e. currently you can differentiate between

test([1, 2]); // one argument that is an array
test(1, 2);   // two arguments that are strings

With such a heuristics, you would not be able to do it any more.

Durnan answered 10/6, 2019 at 4:28 Comment(0)
U
3

It has different results in the function.

1) If you pass multiple strings to the function, it will get an array of strings like so:

test('a', 'series of', 'strings go here');

//vardump result
array (size=3)
  0 => string 'a' (length=1)
  1 => string 'series of' (length=9)
  2 => string 'strings go here' (length=15)

2) If you pass an array to function it will get an array of arrays. The splat operator will add a first entry that you pass to function to the first index of an array, the second parameter will add into the second index and so on. so no matter what you pass to the function (array or string) it will go to index zero. but the problem is if you pass array it will generate an array of arrays in the first index of the array:

test([ 'a', 'series of', 'strings go here' ]);

//vardump result
array (size=1)
  0 => 
    array (size=3)
      0 => string 'a' (length=1)
      1 => string 'series of' (length=9)
      2 => string 'strings go here' (length=15)

Conclusion:

you can solve this with one of these two ways:

1) put 3 dots before you pass the array to the function:

test(...[ 'a', 'series of', 'strings go here' ]);

2) Another way of doing this is by adding a function named is_multi_array() to check if the variable that passed to the function is multi-dimensional. After that you can simply get the first element of the array and put it in strings variable:

function is_multi_array( $arr ) {
    rsort( $arr );
    return (isset( $arr[0] ) && is_array( $arr[0] ));
}

function test(...$strings)
{
   if(is_multi_array($strings)){
       $strings = $strings[0];
   }

   //do the rest
}

This way you can use the function in both ways that you like:

test('a', 'series of', 'strings go here');
test([ 'a', 'series of', 'strings go here' ]);
Unseasonable answered 10/6, 2019 at 4:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.