Jak przekazać zmienną liczbę argumentów do funkcji PHP


115

Mam funkcję PHP, która przyjmuje zmienną liczbę argumentów (używając func_num_args()i func_get_args()), ale liczba argumentów, które chcę przekazać, zależy od długości tablicy. Czy istnieje sposób na wywołanie funkcji PHP ze zmienną liczbą argumentów?


1
Sprawdź moją odpowiedź, aby dowiedzieć się o operatorze splat w nowym php5.6: stackoverflow.com/a/23163963/1090562
Salvador Dali

Odpowiedzi:


132

Jeśli masz swoje argumenty w tablicy, możesz być zainteresowany call_user_func_arrayfunkcją.

Jeśli liczba argumentów, które chcesz przekazać, zależy od długości tablicy, prawdopodobnie oznacza to, że możesz samodzielnie spakować je do tablicy - i użyć tego jako drugiego parametru programu call_user_func_array.

Elementy tej przekazanej tablicy zostaną następnie odebrane przez funkcję jako odrębne parametry.


Na przykład, jeśli masz tę funkcję:

function test() {
  var_dump(func_num_args());
  var_dump(func_get_args());
}

Możesz spakować swoje parametry w tablicę, na przykład:

$params = array(
  10,
  'glop',
  'test',
);

A następnie wywołaj funkcję:

call_user_func_array('test', $params);

Ten kod wyświetli:

int 3

array
  0 => int 10
  1 => string 'glop' (length=4)
  2 => string 'test' (length=4)

tj. 3 parametry; dokładnie tak, jak funkcja iof została wywołana w ten sposób:

test(10, 'glop', 'test');

1
Tak dziękuję. call_user_func_array () to dokładnie ta funkcja, której szukałem.
nohat

Czy jest możliwe użycie call_user_func_array () z wywołaniem metody obiektu?
nohat

6
@nohat: nie ma za co :-) ;; o używaniu metody obiektu: tak, możesz, używając czegoś takiego jak array ($ obj, 'nazwaMetody') jako pierwszego parametru ;; właściwie możesz przekazać dowolne "wywołanie zwrotne" do tej funkcji. Aby uzyskać więcej informacji na temat callbacków, zobacz php.net/callback#language.types.callback
Pascal MARTIN

58

Jest to teraz możliwe w PHP 5.6.x , używając operatora ... (znanego również jako operator splat w niektórych językach):

Przykład:

function addDateIntervalsToDateTime( DateTime $dt, DateInterval ...$intervals )
{
    foreach ( $intervals as $interval ) {
        $dt->add( $interval );
    }
    return $dt;
}

addDateIntervaslToDateTime( new DateTime, new DateInterval( 'P1D' ), 
        new DateInterval( 'P4D' ), new DateInterval( 'P10D' ) );

1
Lista wpisanych zmiennych argumentów jest funkcją wprowadzoną w PHP 7 .
Daniele Orlando


40

Od PHP 5.6 listę argumentów zmiennych można określić za pomocą ...operatora.

function do_something($first, ...$all_the_others)
{
    var_dump($first);
    var_dump($all_the_others);
}

do_something('this goes in first', 2, 3, 4, 5);

#> string(18) "this goes in first"
#>
#> array(4) {
#>   [0]=>
#>   int(2)
#>   [1]=>
#>   int(3)
#>   [2]=>
#>   int(4)
#>   [3]=>
#>   int(5)
#> }

Jak widać, ...operator zbiera zmienną listę argumentów w tablicy.

Jeśli chcesz przekazać zmienne argumenty do innej funkcji, ...nadal może ci pomóc.

function do_something($first, ...$all_the_others)
{
    do_something_else($first, ...$all_the_others);
    // Which is translated to:
    // do_something_else('this goes in first', 2, 3, 4, 5);
}

Od PHP 7 lista zmiennych argumentów może być wymuszona, aby wszystkie były tego samego typu.

function do_something($first, int ...$all_the_others) { /**/ }

11

Dla tych, którzy szukają sposobu na zrobienie tego za pomocą $object->method:

call_user_func_array(array($object, 'method_name'), $array);

Udało mi się to w funkcji konstrukcji, która wywołuje zmienną nazwa_metody ze zmiennymi parametrami.


2
Możesz również skorzystać$object->method_name(...$array);
Yoann Kergall

Idąc dalej, jeśli chcesz przejść przez odniesienie, użyj$object->method_name(&...$args);
Fabien Haddadi

4

Możesz to po prostu nazwać.

function test(){        
     print_r(func_get_args());
}

test("blah");
test("blah","blah");

Wynik:

Tablica ([0] => bla) Tablica ([0] => bla [1] => bla)


Jeśli dobrze rozumiem OP, problem nie polega na odebraniu parametrów, ale wywołaniu funkcji ze zmienną liczbą parametrów.
Pascal MARTIN

1
Wtedy nie zrozumiałem poprawnie OP. W takim razie tablica byłaby zdecydowanie najlepszym rozwiązaniem. Z drugiej strony mógłby po prostu przekazać tablicę bezpośrednio do testu (), nie?
Donnie C

1
Przekazanie tablicy też może być rozwiązaniem, rzeczywiście - jeśli dobrze zrozumiałem ^^
Pascal MARTIN

1
Stare pytanie, ale fyi, tablica działa dobrze, ale przekazywanie rzeczywistych argumentów pozwala na użycie domyślnych wartości PHP dla argumentów zerowych, co oszczędza wiele brzydkich sprawdzeń, czy tablica zawiera określone wartości.
Endophage,


1

Stare pytanie, ale wiem, że żadna z odpowiedzi nie jest tak naprawdę dobra, polegająca na prostej odpowiedzi na pytanie.

Po prostu bawiłem się php i rozwiązanie wygląda następująco:

function myFunction($requiredArgument, $optionalArgument = "default"){
   echo $requiredArgument . $optionalArgument;
}

Ta funkcja może zrobić dwie rzeczy:

Jeśli zostanie wywołany tylko z wymaganym parametrem: myFunction("Hi") wyświetli "Hi default"

Ale jeśli zostanie wywołany z opcjonalnym parametrem: myFunction("Hi","me") wyświetli "Cześć mi";

Mam nadzieję, że pomoże to każdemu, kto szuka tego w przyszłości.


2
Nie zrozumiałeś pytania. OP pytał o argumenty, których nie musiał jawnie definiować w sygnaturze funkcji - mimo to nadal może przekazywać wartości jako argumenty do funkcji. Na przykład sygnatura funkcji nie ma zdefiniowanych żadnych argumentów (opcjonalnych lub nie), ale gdy tego wymaga, OP może wysłać 45 różnych wartości jako argumenty do funkcji.
a20

0

Oto rozwiązanie wykorzystujące magiczną metodę __invoke

(Dostępne od php 5.3)

class Foo {
    public function __invoke($method=null, $args=[]){
        if($method){
            return call_user_func_array([$this, $method], $args);
        }
        return false;
    }

    public function methodName($arg1, $arg2, $arg3){

    }
}

Z wewnątrz tej samej klasy:

$this('methodName', ['arg1', 'arg2', 'arg3']);

Z instancji obiektu:

$obj = new Foo;
$obj('methodName', ['arg1', 'arg2', 'arg3'])

Jest to w zasadzie użycie, call_user_func_arrayjak stwierdzono w odpowiedziach najczęściej głosowanych w 2009 roku. Może jest sens, aby zawijać coś więcej __invoke- ale nie widzę tego.
a20
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.