如何将可变数量的参数传递给PHP函数

124

我有一个 PHP 函数,它接受可变数量的参数(使用 func_num_args()func_get_args()),但是我想要传递给函数的参数数量取决于一个数组的长度。有没有一种方法可以使用可变数量的参数 调用 PHP 函数?


1
请查看我的答案,了解新的php5.6中的splat运算符:https://dev59.com/aHM_5IYBdhLWcg3wUxjF#23163963 - Salvador Dali
11个回答

136
如果你的参数在一个数组中,你可能会对call_user_func_array 函数感兴趣。
如果要传递的参数数量取决于数组的长度,那么你可以将它们打包成一个数组,并将其用作call_user_func_array的第二个参数。
你传递的数组元素将作为独立的参数被接收到你的函数中。
例如,如果你有这个函数:
function test() {
  var_dump(func_num_args());
  var_dump(func_get_args());
}
您可以将参数打包到数组中,像这样:

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

接下来,调用该函数:

call_user_func_array('test', $params);

此代码将输出:

int 3

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

比如说,有3个参数;就像函数被这样调用:

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

1
是的,谢谢。call_user_func_array()正是我正在寻找的函数。 - nohat
能否在对象方法调用中使用call_user_func_array()函数? - nohat
6
@nohat:不用谢 :-);关于使用对象的方法:是的,你可以使用类似 array($obj, 'methodName') 的方式作为第一个参数;实际上,你可以传递任何你想要的“回调”函数给那个函数。有关回调函数的更多信息,请参见 http://php.net/callback#language.types.callback. - Pascal MARTIN

64
现在,使用运算符(在某些语言中也称为splat运算符)可以实现 PHP 5.6.x,例如:

示例:

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' ) );

3
Typed 变量参数列表” 是在 PHP 7 中引入的一项功能。 - Daniele Orlando

52
在新的Php 5.6中,您可以使用... operator而不是使用func_get_args()来获取传递的所有参数。

因此,使用它,您可以获取传递的所有参数:

function manyVars(...$params) {
   var_dump($params);
}

3
这里有更多信息:http://php.net/manual/zh/migration56.new-features.php#migration56.new-features.variadics。 - fracz
从@fracz的链接中可以看出,OP正在尝试创建一个“可变参数函数”。 - Nathan Arthur

50

自从PHP 5.6起,可以使用...运算符指定变量参数列表。

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)
#> }

正如您所看到的,...运算符将参数列表收集到一个数组中。

如果您需要将可变参数传递给另一个函数,则...仍然可以帮助您。

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);
}
自从PHP 7起,可变参数列表也可以被强制要求全部是相同的类型。
function do_something($first, int ...$all_the_others) { /**/ }

11

如果您正在寻找一种使用$object->method来完成此操作的方法:

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

我在一个构造函数中成功地使用了这个方法,该方法调用了一个带有变量参数的变量 method_name。


2
您还可以使用 $object->method_name(...$array); - Yoann Kergall
更进一步,如果您想按引用传递参数,请使用 $object->method_name(&...$args); - Fabien Haddadi

5
你可以直接调用它。
function test(){        
     print_r(func_get_args());
}

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

输出:

数组([0] => blah) 数组([0] => blah [1] => blah)


如果我理解 OP 的意思正确的话,问题不在于接收参数,而是在于使用可变数量的参数来 调用函数 - Pascal MARTIN
1
我没有正确理解 OP 的意思。那么使用数组肯定是最好的方法。不过,他也可以直接将数组传递给 test(),对吧? - Donnie C
1
传递一个数组也可能是一个解决方案,确实如此——如果我理解正确的话 ^^ - Pascal MARTIN
1
虽然这是一个老问题,但是如果你传递实际参数,PHP的默认值可以用于空参数,这样可以避免许多不美观的检查操作,使用数组也是可以的。 - Endophage

3
我想知道关于使用命名参数(自PHP 8以来)与可变参数的结合可能性的文档,但我找不到。因为我尝试了这段代码,我很惊讶它竟然可以工作:
function myFunc(...$args) {
    foreach ($args as $key => $arg) {
        echo "Key: $key Arg: $arg <br>";
    }
}
echo myFunc(arg1:"foo", arg2:"bar");

输出:

Key: arg1 Arg: foo
Key: arg2 Arg: bar

在我看来,这非常酷。

1
我很惊讶这里没有人提到简单地传递和提取一个数组。例如:
function add($arr){
    extract($arr, EXTR_REFS);
    return $one+$two;
}
$one = 1;
$two = 2;
echo add(compact('one', 'two')); // 3

当然,这并未提供参数验证。 为此,任何人都可以使用我的expect函数:https://gist.github.com/iautomation/8063fc78e9508ed427d5

extract 不应该被使用... 使用它是一个非常糟糕的想法。 - PapsOu

0

这是一个老问题,我知道,然而,这里的任何答案都没有很好地回答这个问题。

我刚刚尝试了一下 PHP,解决方案看起来像这样:

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

这个函数可以做两件事情:

如果只使用必需的参数调用它:myFunction("Hi") 它将打印出 "Hi default"

但是,如果使用可选参数调用它:myFunction("Hi","me") 它将打印出 "Hi me";

我希望这能帮助那些在未来需要这个的人。


3
你没有理解问题。OP问的是关于在函数签名中不必明确定义的参数,但仍然可以将值作为参数传递给函数。例如,函数签名没有定义任何参数(可选或非可选),但当需要时,OP可以将45个不同的值作为参数发送到函数中。 - a20

0
这里是一个使用魔术方法 __invoke 的解决方案。 (自 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){

    }
}

在同一个类中:

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

从一个对象的实例:

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

这基本上是使用call_user_func_array,正如2009年最受欢迎的答案所述。也许在它周围包装一个额外的__invoke有点意义,但我看不出来。 - a20

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接