我对PHP函数的默认值感到困惑。假设我有一个这样的函数:

function foo($blah, $x = "some value", $y = "some other value") {
    // code here!
}

如果我想使用$x的默认参数,并为$y设置一个不同的参数呢?

我一直在尝试不同的方法,但我越来越困惑了。例如,我尝试了以下两种:

foo("blah", null, "test");
foo("blah", "", "test");

但这两种方法都不会为$x提供合适的默认参数。我还尝试通过变量名来设置它。

foo("blah", $x, $y = "test");   

我满心期待这样的东西能起作用。但它完全不像我想象的那样。似乎无论我做什么,每次调用函数时,我都必须输入默认参数。我肯定遗漏了一些明显的东西。


当前回答

<?php
function info($name="George",$age=18) {
echo "$name is $age years old.<br>";
}
info();     // prints default values(number of values = 2)
info("Nick");   // changes first default argument from George to Nick
info("Mark",17);    // changes both default arguments' values

?>

其他回答

<?php
function info($name="George",$age=18) {
echo "$name is $age years old.<br>";
}
info();     // prints default values(number of values = 2)
info("Nick");   // changes first default argument from George to Nick
info("Mark",17);    // changes both default arguments' values

?>

可选参数只在函数调用结束时起作用。如果不指定$x,就无法在函数中指定$y的值。有些语言通过命名参数(例如VB/ c#)支持这一点,但PHP不支持。

如果你使用一个关联数组代替参数,你可以模拟这一点。

function foo(array $args = array()) {
    $x = !isset($args['x']) ? 'default x value' : $args['x'];
    $y = !isset($args['y']) ? 'default y value' : $args['y'];

    ...
}

然后像这样调用函数:

foo(array('y' => 'my value'));

我的2美分与空合并运算符??(从PHP 7开始)

function foo($blah, $x = null, $y = null) {
    $varX = $x ?? 'Default value X';
    $varY = $y ?? 'Default value Y';
    // ...
}

你可以在我的replyit上查看更多的例子

我建议修改函数声明如下,这样你就可以做你想做的事情:

function foo($blah, $x = null, $y = null) {
    if (null === $x) {
        $x = "some value";
    }

    if (null === $y) {
        $y = "some other value";
    }

    code here!

}

这样,你可以调用foo('blah', null, '非默认y值');让它像你想要的那样工作,其中第二个参数$x仍然得到它的默认值。

使用此方法,传递空值意味着当您希望覆盖后面的参数的默认值时,需要一个参数的默认值。

如其他答案所述,

默认形参仅作为函数的最后一个实参。 如果你想在函数定义中声明默认值, 没有办法省略一个参数并覆盖它后面的一个参数。

如果我有一个方法可以接受不同数量的参数,以及不同类型的参数,我通常声明的函数类似于Ryan P。

下面是另一个例子(这不能回答你的问题,但希望能提供信息:

public function __construct($params = null)
{
    if ($params instanceof SOMETHING) {
        // single parameter, of object type SOMETHING
    } elseif (is_string($params)) {
        // single argument given as string
    } elseif (is_array($params)) {
        // params could be an array of properties like array('x' => 'x1', 'y' => 'y1')
    } elseif (func_num_args() == 3) {
        $args = func_get_args();

        // 3 parameters passed
    } elseif (func_num_args() == 5) {
        $args = func_get_args();
        // 5 parameters passed
    } else {
        throw new \InvalidArgumentException("Could not figure out parameters!");
    }
}

这实际上是可能的:

foo( 'blah', (new ReflectionFunction('foo'))->getParameters()[1]->getDefaultValue(), 'test');

你是否想这样做是另一个故事:)


更新:

避免这种解决方案的原因是:

它(可以说)丑陋 它有一个明显的开销。 正如其他答案所证明的那样,还有其他选择

但它实际上在以下情况下很有用:

你不想/不能改变原来的函数。 你可以改变函数,但是: 使用空(或等效)不是一个选项(见DiegoDD的评论) 你既不想使用associative也不想使用func_num_args() 你的命就靠救几个人质了

关于性能,一个非常简单的测试表明,使用Reflection API获取默认参数会使函数调用变慢25倍,但仍然需要不到1微秒的时间。你应该知道你能不能接受。

当然,如果您打算在循环中使用它,则应该事先获取默认值。