Передача массива как аргумента, а не массива в PHP


148

Кажется, я помню, что в PHP есть способ передать массив в виде списка аргументов для функции, разыменовывая массив стандартным func($arg1, $arg2)способом. Но теперь я заблудился, как это сделать. Я вспоминаю способ передачи по ссылке, как «глобализировать» входящие параметры ... но не как вывести массив из списка аргументов.

Это может быть так просто func(&$myArgs), но я уверен, что это не так. Но, к сожалению, руководство php.net пока ничего не разглашает. Не то чтобы я использовал эту особенность в течение последнего года или около того.

Ответы:


178

1
Я мог бы поклясться, что это тоже не-функция, вроде префиксного символа или чего-то еще. Спасибо.
Роберт К

8
Но я не знаю Python! Я должен быть случайно экстрасенсом ...: D
Роберт К

45
Распаковка аргумента, как она называется, будет добавлена ​​в PHP 5.6 ( wiki.php.net/rfc/argument_unpacking ). Он будет использовать оператор «splat»: «...». Его синтаксис: $args = [1,2,3]; function(...$args){}
arothuis

4
но что, если функция, которую вы хотите вызвать, является методом экземпляра объекта, а не именем функции в глобальном пространстве?
Анбизкад

6
@ahnbizcad, тогда вы должны использовать a callable, который использует то же самое call_user_func_array, только с массивом, где первый элемент - объект, а второй - метод. Напримерcall_user_func_array([$object, 'method'], $myArgs);
SteveB

149

Как уже упоминалось , начиная с PHP 5.6+ вы можете (должны!) Использовать ...токен (он же «оператор сплат », часть функциональности функций с переменными числами ), чтобы легко вызывать функцию с массивом аргументов:

<?php
function variadic($arg1, $arg2)
{
    // Do stuff
    echo $arg1.' '.$arg2;
}

$array = ['Hello', 'World'];

// 'Splat' the $array in the function call
variadic(...$array);

// 'Hello World'

Примечание. Элементы массива сопоставляются с аргументами по их положению в массиве, а не по ключам.

Согласно комментарию CarlosCarucce в это форма аргумента распаковки является самым быстрым способом на сегодняшний день во всех случаях. В некоторых сравнениях это более чем в 5 раз быстрее, чем call_user_func_array.

В стороне

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

(Просто помните, что при этом ДОЛЖЕН быть последний заданный вами параметр и он объединяет все параметры, переданные функции в массив.)

Это отлично подходит для того, чтобы убедиться, что массив содержит элементы определенного типа:

<?php

// Define the function...

function variadic($var, SomeClass ...$items)
{
    // $items will be an array of objects of type `SomeClass`
}

// Then you can call...

variadic('Hello', new SomeClass, new SomeClass);

// or even splat both ways

$items = [
    new SomeClass,
    new SomeClass,
];

variadic('Hello', ...$items);

7
Это значительно улучшило производительность call_user_func_array. Так что если вы используете php 5.6+, я бы порекомендовал этот. Вот тест , который был процитирован в официальном php wiki
CarlosCarucce

2
К сожалению, это не помеченный ответ. Определенно лучше
unforgiven1987

81

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

call_user_func_array(array($instance, "MethodName"), $myArgs);

4
@understack $foo->bar()Пример на связанной странице предполагает, что так и должно быть array($instance, "MethodName").
Пол Калкрафт

11
Круто, я использовал это, чтобы избежать дублирования аргументов конструктора в дочернем классе :)call_user_func_array(array(parent, "__construct"), func_get_args());
Джейсон

10

Для полноты, с PHP 5.1 это тоже работает:

<?php
function title($title, $name) {
    return sprintf("%s. %s\r\n", $title, $name);
}
$function = new ReflectionFunction('title');
$myArray = array('Dr', 'Phil');
echo $function->invokeArgs($myArray);  // prints "Dr. Phil"
?>

Смотрите: http://php.net/reflectionfunction.invokeargs

Для методов вы используете ReflectionMethod :: invokeArgs вместо этого и передаете объект в качестве первого параметра.


На самом деле это то, что я искал!
Дейв
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.