在函数中使用默认参数

ren*_*sis 166 php arguments default

我对PHP函数的默认值感到困惑.说我有这样的功能:

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

如果我想使用$ x的默认参数并为$ y设置不同的参数,该怎么办?

我一直在尝试不同的方式,我只是变得更加困惑.例如,我尝试了这两个:

foo("blah", null, "test");
foo("blah", "", "test");
Run Code Online (Sandbox Code Playgroud)

但是这两个都不会导致$ x的正确默认参数.我也尝试用变量名设置它.

foo("blah", $x, $y = "test");   
Run Code Online (Sandbox Code Playgroud)

我完全期望这样的事情能发挥作用.但它根本无法实现.似乎无论我做什么,每次调用函数时,我都必须最终输入默认参数.而且我必须遗漏一些明显的东西.

dre*_*010 153

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

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

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

    code here!

}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以进行调用foo('blah', null, 'non-default y value');,并使其按预期工作,其中第二个参数$x仍然可以获得其默认值.

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

如其他答案所述,

默认参数仅作为函数的最后一个参数.如果要在函数定义中声明默认值,则无法省略一个参数并覆盖其后的一个参数.

如果我有一个可以接受不同数量的参数,以及不同类型的参数的方法,我常常声明类似于由Ryan P.所示的答案功能

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

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

        // 3 parameters passed
    } else if (func_num_args() == 5) {
        $args = func_get_args();
        // 5 parameters passed
    } else {
        throw new InvalidArgumentException("Could not figure out parameters!");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 只是为了给未来的读者澄清一下.第一个解决方案显然不可能为参数分配一个真正的`null`值,因为每次它都会分配默认值.即使你在实际需要null时有另一个特殊值(例如当$ x =="use_null"make $ x = null),那么你将无法分配这样的特殊值作为文字的值.参数(在本例中为"use_null"字符串).因此,当您想要使用默认值(并且希望`null`是有效选项)时,请务必使用唯一的,永不需要的"键". (9认同)

Rya*_*n P 37

可选参数仅在函数调用结束时起作用.如果没有指定$ 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'];

    ...
}
Run Code Online (Sandbox Code Playgroud)

然后像这样调用函数:

foo(array('y' => 'my value'));
Run Code Online (Sandbox Code Playgroud)


Dav*_*vid 20

它实际上是可能的:

foo( 'blah', (new ReflectionFunction('foo'))->getParameters()[1]->getDefaultValue(), 'test');
Run Code Online (Sandbox Code Playgroud)

你是否愿意这样做是另一回事:)


更新:

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

  • 它(可以说)是丑陋的
  • 它有明显的开销.
  • 正如另一个回答证明,有其他选择

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

  • 你不希望/不能改变原来的功能.
  • 你可以改变功能但是:

    • 使用null(或等效)不是一种选择(参见DiegoDD的评论)
    • 你不想用关联或用 func_num_args()
    • 你的生活取决于拯救几个LOC

关于性能,一个非常简单的测试表明,使用Reflection API获取默认参数会使函数调用慢25倍,而它仍然需要不到1微秒.你应该知道你是否可以忍受.

当然,如果你想在循环中使用它,你应该事先得到默认值.

  • @Bryan.我已经更新了答案. (2认同)

zlo*_*ctb 10

function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

  • @SeantheBean:是的,解释会更好,但他的观点是:由于PHP没有命名参数,因此使用关联数组作为其单个参数. (3认同)
  • 我错过了什么吗?这似乎根本没有回答这个问题,但它有7个赞成票.也许添加一些解释会有帮助吗? (2认同)
  • 使用问题中给出的示例更有帮助,例如`$defaults = [ 'x' => 'some value', 'y' => 'some other value'];` (2认同)

Aam*_*irR 9

PHP 8 使用命名参数

如果我想使用参数 $x 的默认值并为 $y 设置值怎么办? foo($blah, $x = "some value", $y = "some other value")

用法1:

foo(blah: "blah", y: "test");
Run Code Online (Sandbox Code Playgroud)

用法2:

// use names to address last arguments
foo("blah", y: "test");
Run Code Online (Sandbox Code Playgroud)

原生函数也会使用这个特性

htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
Run Code Online (Sandbox Code Playgroud)

关于功能和文档

命名参数允许根据参数名称而不是参数位置将参数传递给函数。这使得参数的含义自文档化,使参数与顺序无关,并允许任意跳过默认值

IDE支持

Netbeans 12.3 完全支持 PHP 8.0 语法,包括此功能,但命名参数的代码完成除外。


Wes*_*row 5

我知道这样做的唯一方法是省略参数。省略参数的唯一方法是重新排列参数列表,以便您要省略的参数位于您必须设置的参数之后。例如:

function foo($blah, $y = "some other value", $x = "some value")
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样调用 foo:

foo("blah", "test");
Run Code Online (Sandbox Code Playgroud)

这将导致:

$blah = "blah";
$y = "test";
$x = "some value";
Run Code Online (Sandbox Code Playgroud)