Как заставить PHP понимать * или * массив или оператор splat (3 точки ...) для параметров функции? - PullRequest
4 голосов
/ 10 июня 2019

У меня есть этот код:

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

Это позволяет мне вызывать test () следующим образом:

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

Что работает.Однако я часто хотел бы сделать:

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

Или:

test($an_array_of_strings);

На самом деле я был настолько уверен, что это сработало, что я был шокирован и растерян, когда начал получать ошибкиabout "Преобразование массива в строку".

Я имею в виду, синтаксис "..." - это специальная языковая конструкция, специально предназначенная для преобразования переменного числа аргументов функции в массив!Я даже не понимаю, почему он не может автоматически понять эту очень распространенную / полезную практику.

Поскольку это (по-видимому) не дает, есть ли способ сделать это без использования двух отдельных функций?Я не хочу отдельное:

function test_array($strings = [])
{
    // ...
}

Ответы [ 2 ]

5 голосов
/ 10 июня 2019

У этой функции разные результаты.

1) Если вы передадите в функцию несколько строк, она получит массив строк, например:

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) Если вы передадите массив в функцию, он получит массив массивов. Оператор splat добавит первую запись, которую вы передадите функции, в первый индекс массива, второй параметр добавит во второй индекс и так далее. поэтому независимо от того, что вы передадите в функцию (массив или строку), она пойдет до нулевого индекса. но проблема в том, что если вы передадите массив, он сгенерирует массив массивов в первом индексе массива:

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)

Вывод:

Вы можете решить эту проблему одним из следующих двух способов:

1) поставить 3 точки перед передачей массива в функцию:

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

2) Другой способ сделать это - добавить функцию с именем is_multi_array (), чтобы проверить, является ли переменная, переданная в функцию, многомерной. После этого вы можете просто получить первый элемент массива и поместить его в строковую переменную:

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
}

Таким образом, вы можете использовать эту функцию двумя способами:

test('a', 'series of', 'strings go here');
test([ 'a', 'series of', 'strings go here' ]);
4 голосов
/ 10 июня 2019

То же самое в обратном порядке:

test(...$an_array_of_strings);

Если вы хотите сделать это автоматическим (чтобы вам не приходилось использовать ... для разбивки массива на аргументы), вам нужно будет проверить вручную, если $strings имеет только один элемент, который массив; затем вы отключите его вручную внутри функции, если это так. Это лишает вас возможности передавать один массив в качестве одного аргумента, и я бы не рекомендовал его. То есть В настоящее время вы можете различить

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

При такой эвристике вы больше не сможете это делать.

...