24

假设我有一个 PHP 函数 foo:

function foo($firstName = 'john', $lastName = 'doe') {
    echo $firstName . " " . $lastName;
}
// foo(); --> john doe

有没有办法只指定第二个可选参数?

例子:

foo($lastName='smith'); // output: john smith
4

13 回答 13

34

PHP 本身不支持函数的命名参数。但是,有一些方法可以解决这个问题:

  1. 使用数组作为函数的唯一参数。然后您可以从数组中提取值。这允许在数组中使用命名参数。
  2. 如果要根据上下文允许可选数量的参数,则可以使用 func_num_args 和 func_get_args 而不是在函数定义中指定有效参数。然后根据参数数量、字符串长度等,您可以确定要做什么。
  3. 将空值传递给您不想指定的任何参数。并没有真正绕过它,但它确实有效。
  4. 如果您在对象上下文中工作,那么您可以使用魔术方法 __call() 来处理这些类型的请求,以便您可以根据传递的参数路由到私有方法。
于 2009-03-27T17:08:49.340 回答
23

数组技术的一种变体,可以更轻松地设置默认值:

function foo($arguments) {
  $defaults = array(
    'firstName' => 'john',
    'lastName' => 'doe',
  );

  $arguments = array_merge($defaults, $arguments);

  echo $arguments['firstName'] . ' ' . $arguments['lastName'];
}

用法:

foo(array('lastName' => 'smith')); // output: john smith
于 2009-03-27T17:29:09.120 回答
9

您可以稍微重构您的代码:

function foo($firstName = NULL, $lastName = NULL)
{
    if (is_null($firstName))
    {
        $firstName = 'john';
    }
    if (is_null($lastName ))
    {
        $lastName = 'doe';
    }

    echo $firstName . " " . $lastName;
}

foo(); // john doe
foo('bill'); // bill doe
foo(NULL,'smith'); // john smith
foo('bill','smith'); // bill smith
于 2009-03-27T17:48:20.430 回答
6

如果您有多个可选参数,一种解决方案是传递一个散列数组参数:

function foo(array $params = array()) {
    $firstName = array_key_exists("firstName", $params) ?
      $params["firstName"] : "";
    $lastName = array_key_exists("lastName", $params) ?
      $params["lastName"] : "";
    echo $firstName . " " . $lastName;
}

foo(['lastName'=>'smith']);

当然,在这个解决方案中,没有验证哈希数组的字段是否存在或拼写正确。这完全取决于您来验证。

于 2009-03-27T17:09:33.190 回答
3

不,通常的做法是使用一些启发式方法来确定隐含的参数,如字符串长度、类型等。

一般来说,您会编写函数以按照最需要到最不需要的顺序获取参数。

于 2009-03-27T17:02:45.733 回答
3

你想要的方式:不。

您可以使用一些特殊标记,例如 NULL 来注意未提供值:

function foo($firstName, $lastName = 'doe') {
    if (is_null($firstName))
        $firstName = 'john';
    echo $firstName . " " . $lastName;
}

foo(null, 'smith');
于 2009-03-27T17:08:09.903 回答
3

PHP 8 引入了命名参数,因此现在可以指定传递给函数的参数。

PHP 8 之前:

htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);

PHP 8 之后:

htmlspecialchars($string, double_encode: false);

参考

于 2020-12-18T18:10:50.537 回答
2

我希望这个解决方案在我 2.5 年前开始使用 PHP 时就已经存在了。它在我创建的示例中效果很好,我不明白为什么它不应该是完全可扩展的。与之前提出的那些相比,它提供了以下好处:

(i) 函数内对参数的所有访问都是通过命名变量进行的,就好像参数已完全声明一样,而不需要数组访问

(ii) 调整现有功能非常快速和容易

(iii) 任何函数只需要一行额外的代码(除了不可避免地需要定义默认参数,无论如何您都将在函数签名中执行此操作,而是在数组中定义它们)。额外线路的功劳完全归功于 Bill Karwin。这条线对于每个功能都是相同的。

方法

使用强制参数和可选数组定义您的函数

将可选参数声明为局部变量

症结:使用您通过数组传递的参数替换任何可选参数的预先声明的默认值。

extract(array_merge($arrDefaults, array_intersect_key($arrOptionalParams, $arrDefaults)));

调用函数,传递它的强制参数,并且只传递你需要的那些可选参数

例如,

function test_params($a, $b, $arrOptionalParams = array()) {

$arrDefaults = array('c' => 'sat',

                     'd' => 'mat');

extract(array_merge($arrDefaults, array_intersect_key($arrOptionalParams, $arrDefaults)));

echo "$a $b $c on the $d";

}

然后这样称呼它

test_params('The', 'dog', array('c' => 'stood', 'd' => 'donkey'));
test_params('The', 'cat', array('d' => 'donkey'));
test_params('A', 'dog', array('c' => 'stood'));

结果:

狗站在驴子上

猫坐在驴子上

一只狗站在垫子上

于 2015-08-19T14:54:28.770 回答
1

这里提到了一些“选项”样式的实现。如果您打算将它们用作标准,那么到目前为止,没有一个是非常防弹的。试试这个模式:

function some_func($required_parameter, &$optional_reference_parameter = null, $options = null) {
    $options_default = array(
        'foo' => null,
    );
    extract($options ? array_intersect_key($options, $options_default) + $options_default : $options_default);
    unset($options, $options_default);

    //do stuff like
    if ($foo !== null) {
        bar();
    }
}

这为您提供了函数局部变量(仅$foo在此示例中)并防止创建任何没有默认值的变量。这样就不会有人意外覆盖函数中的其他参数或其他变量。

于 2014-04-11T06:34:16.993 回答
1

参数需要按位置顺序传递,不能跳过参数本身;您必须提供默认参数值才能跳过它。可以说,这违背了你想要达到的目的。

在不重写函数以不同方式接受参数的情况下,这是一种解决此问题的调用时方法:

$func = 'foo';
$args = ['lastName' => 'Smith'];

$ref = new ReflectionFunction($func);
$ref->invokeArgs(array_map(function (ReflectionParameter $param) use ($args) {
    if (array_key_exists($param->getName(), $args)) {
        return $args[$param->getName()];
    }
    if ($param->isOptional()) {
        return $param->getDefaultValue();
    }
    throw new InvalidArgumentException("{$param->getName()} is not optional");
}, $ref->getParameters()));

换句话说,您使用反射来检查函数的参数并按名称将它们映射到可用参数,跳过带有默认值的可选参数。是的,这既丑陋又麻烦。您可以使用此示例创建一个函数,例如:

call_func_with_args_by_name('foo', ['lastName' => 'Smith']);
于 2015-08-26T09:11:41.407 回答
0

可悲的是,您尝试做的事情没有“语法糖”的方式。它们都是不同形式的 WTF。

如果您需要一个带有未定义数量的任意参数的函数,

function foo () { 
     $args = func_get_args(); 
     # $args = arguments in order 
}

会成功的。尽量避免使用太多,因为对于 PHP,这有点神奇。

然后,您可以选择应用默认值并根据参数计数做一些奇怪的事情。

function foo() { 
   $args = func_get_args();
   if (count($args) < 1 ) { 
       return "John Smith"; 
   }
   if (count($args) < 2 ) { 
       return "John " . $args[0];
   }
   return $args[0] . " " . $args[1];
}

此外,您可以选择模拟 Perl 样式参数,

function params_collect($arglist){ 
    $config = array();
    for ($i = 0; $i < count($arglist); $i+=2) { 
        $config[$i] = $config[$i+1];
    }
    return $config; 
}
function param_default($config, $param, $default){ 
    if (!isset($config[$param])) { 
        $config[$param] = $default;
    }
    return $config;
}

function foo() { 
   $args = func_get_args();
   $config = params_collect($args); 
   $config = param_default($config, 'firstname', 'John'); 
   $config = param_default($config, 'lastname', 'Smith'); 
   return $config['firstname'] . ' ' . $config['lastname'];   
}

foo('firstname', 'john', 'lastname', 'bob'); 
foo('lastname', 'bob', 'firstname', 'bob'); 
foo('firstname', 'smith'); 
foo('lastname', 'john');

当然,在这里使用数组参数更容易,但是您可以选择(甚至是不好的方式)做事。

值得注意的是,这在 Perl 中更好,因为你可以只做 foo(firstname => 'john');

于 2009-03-27T17:11:47.147 回答
0

如果经常使用,只需定义一个新的专用函数:

function person($firstName = 'john', $lastName = 'doe') {
    return $firstName . " " . $lastName;
}

function usualFirtNamedPerson($lastName = 'doe') {
    return person('john', $lastName);
}

print(usualFirtNamedPerson('smith')); --> john smith

请注意,如果您愿意,您还可以在此过程中更改 $lastname 的默认值。

当一个新函数估计过大时,只需调用带有所有参数的函数即可。如果你想让它更清楚,你可以将你的文字预先存储在 fin 命名变量中或使用注释。

$firstName = 'Zeno';
$lastName = 'of Elea';
print(person($firstName, $lastName));
print(person(/* $firstName = */ 'Bertrand', /* $lastName = */ 'Russel'));

好的,这不像 那样简短优雅person($lastName='Lennon'),但似乎你不能在 PHP 中拥有它。这不是最性感的编码方式,使用超级元编程技巧或其他方式,但您希望在维护过程中遇到什么解决方案?

于 2016-11-15T09:33:23.247 回答
-1

不,没有,但您可以使用数组:

function foo ($nameArray) {
    // Work out which values are missing?
    echo $nameArray['firstName'] . " " . $nameArray['lastName'];
}

foo(array('lastName'=>'smith'));
于 2009-03-27T17:09:55.607 回答