在PHP中指定可选参数值的任何方法?

时间:2022-12-28 10:57:14

Let's say I've got a PHP function foo:

假设我有一个PHP函数foo:

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

Is there any way to specify only the second optional parameter?

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

Example:

例:

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

12 个解决方案

#1


32  

PHP does not support named parameters for functions per se. However, there are some ways to get around this:

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

  1. Use an array as the only argument for the function. Then you can pull values from the array. This allows for using named arguments in the array.
  2. 使用数组作为函数的唯一参数。然后,您可以从数组中提取值。这允许在数组中使用命名参数。
  3. If you want to allow optional number of arguments depending on context, then you can use func_num_args and func_get_args rather than specifying the valid parameters in the function definition. Then based on number of arguments, string lengths, etc you can determine what to do.
  4. 如果要根据上下文允许可选数量的参数,则可以使用func_num_args和func_get_args,而不是在函数定义中指定有效参数。然后根据参数数量,字符串长度等,您可以确定要执行的操作。
  5. Pass a null value to any argument you don't want to specify. Not really getting around it, but it works.
  6. 将null值传递给您不想指定的任何参数。没有真正解决它,但它的工作原理。
  7. If you're working in an object context, then you can use the magic method __call() to handle these types of requests so that you can route to private methods based on what arguments have been passed.
  8. 如果您正在使用对象上下文,则可以使用magic方法__call()来处理这些类型的请求,以便您可以根据传递的参数路由到私有方法。

#2


21  

A variation on the array technique that allows for easier setting of default values:

阵列技术的一种变体,可以更容易地设置默认值:

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

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

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

Usage:

用法:

foo(array('lastName' => 'smith')); // output: john smith

#3


9  

You could refactor your code slightly:

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

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

#4


6  

If you have multiple optional parameters, one solution is to pass a single parameter that is a hash-array:

如果您有多个可选参数,则一种解决方案是传递一个哈希数组的参数:

function foo(array $params = array()) {
    echo $params['firstName'] . " " . $params['lastName'];
}

foo(array('lastName'=>'smith'));

Of course in this solution there's no validation that the fields of the hash array are present, or spelled correctly. It's all up to you to validate.

当然,在此解决方案中,无法验证散列数组的字段是否存在或拼写正确。这完全由你来验证。

#5


3  

No. The usual way of doing this is with some heuristics to determine which parameter was implied, like string length, typing, etc.

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

Generally speaking, you'd write the function to take the parameters in the order of most required to least required.

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

#6


3  

The way you want: no.

你想要的方式:没有。

You could use some special mark, like NULL to note that value is not supplied:

你可以使用一些特殊的标记,比如NULL,注意不提供值:

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

foo(null, 'smith');

#7


1  

There are a few 'options' style implementations mentioned here. None thus far are very bulletproof if you plan to use them as as standard. Try this pattern:

这里提到了一些“选项”样式实现。如果你计划将它们作为标准使用,到目前为止都没有防水措施。试试这种模式:

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();
    }
}

This gives you function-local variables (just $foo in this example) and prevents creating any variables that do not have a default. This is so no one can accidentally overwrite other parameters or other variables within the function.

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

#8


1  

Arguments need to be passed in order by position, you cannot skip a parameter per se; you'll have to supply the default parameter value in order to skip it. Arguably that defeats the purpose of what you're trying to achieve.

参数需要按位置顺序传递,你不能跳过参数本身;你必须提供默认参数值才能跳过它。可以说,这打败了你想要实现的目标。

Without rewriting your function to accept parameters differently, here's a call-time way to work around this:

如果不重写您的函数以接受不同的参数,这里有一个调用时间方法来解决这个问题:

$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()));

In other words, you're using reflection to inspect the function's parameters and map them to the available parameters by name, skipping optional parameters with their default value. Yes, this is ugly and cumbersome. You could use this sample to create a function like:

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

call_func_with_args_by_name('foo', ['lastName' => 'Smith']);

#9


1  

I wish this solution had been on SO when I started using PHP 2.5 years ago. It works great in the examples I have created, and I don't see why it shouldn't be thoroughly extensible. It offers the following benefits over those proposed previously:

我希望这个解决方案在我2.5年前开始使用PHP时就已经存在了。它在我创建的示例中运行良好,我不明白为什么它不应该是完全可扩展的。它提供了以前提出的优点:

(i) all access to parameters within the function is by named variables, as if the parameters were fully declared, rather than requiring array access

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

(ii) it is very quick and easy to adapt existing functions

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

(iii) only a single line of additional code is required for any function (in addition to the inescapable necessity of defining your default parameters, which you would be doing in the function signature anyway, but instead you define them in an array). Credit for the additional line is wholly due to Bill Karwin. This line is identical for every function.

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

Method

方法

Define your function with its mandatory parameters, and an optional array

使用必需参数和可选数组定义函数

Declare your optional parameters as local variables

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

The crux: replace the pre-declared default value of any optional parameters using those you have passed via the array.

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

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

Call the function, passing its mandatory parameters, and only those optional parameters that you require

调用该函数,传递其必需参数,并仅传递您需要的可选参数

For example,

例如,

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";

}

and then call it like this

然后像这样调用它

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

Results:

结果:

The dog stood on the donkey

那只狗站在驴上

The cat sat on the donkey

那只猫坐在驴上

A dog stood on the mat

一条狗站在垫子上

#10


0  

If this is used very often, just define a new specialized function :

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

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

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

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

Note that you could also change the default value of $lastname in the process if you wish.

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

When a new function is estimated overbloated, just call you function with all parameters. If you want to make it more clear, you can prestore your literals in fin named variable or use comments.

当一个新函数被估计为overbloated时,只需使用所有参数调用函数。如果您想更清楚,可以在fin命名变量中预存文字或使用注释。

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

Ok, this is not as short and elegant as person($lastName='Lennon'), but it seems you can't have it in PHP. And that's not the sexiest way to code it, with super metaprogramming trick or whatever, but what solution would you prefer to encounter in a maintenance process?

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

#11


-1  

Sadly what you're trying to do has no "syntactic sugar" way of doing it. They're all varying forms of WTF.

可悲的是,你正在尝试做的事情没有“语法糖”的方式。它们都是各种形式的WTF。

If you need a function that takes an undefined number of arbitrary parameters,

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

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

Will do the trick. Try avoid using it too much, because for Php this is a bit on the magical side.

会做的伎俩。尽量避免使用太多,因为对于Php来说,这有点神奇。

You could then optionally apply defaults and do strange things based on parameter count.

然后,您可以选择应用默认值并根据参数计数执行奇怪的操作。

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];
}

Also, you could optionally emulate Perl style parameters,

此外,您可以选择模拟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' );

Of course, it would be easier to use an array argument here, but you're permitted to have choice ( even bad ways ) of doing things.

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

notedly, this is nicer in Perl because you can do just foo( firstname => 'john' );

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

#12


-1  

No there isn't but you could use an array:

没有,但你可以使用数组:

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

foo(array('lastName'=>'smith'));

#1


32  

PHP does not support named parameters for functions per se. However, there are some ways to get around this:

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

  1. Use an array as the only argument for the function. Then you can pull values from the array. This allows for using named arguments in the array.
  2. 使用数组作为函数的唯一参数。然后,您可以从数组中提取值。这允许在数组中使用命名参数。
  3. If you want to allow optional number of arguments depending on context, then you can use func_num_args and func_get_args rather than specifying the valid parameters in the function definition. Then based on number of arguments, string lengths, etc you can determine what to do.
  4. 如果要根据上下文允许可选数量的参数,则可以使用func_num_args和func_get_args,而不是在函数定义中指定有效参数。然后根据参数数量,字符串长度等,您可以确定要执行的操作。
  5. Pass a null value to any argument you don't want to specify. Not really getting around it, but it works.
  6. 将null值传递给您不想指定的任何参数。没有真正解决它,但它的工作原理。
  7. If you're working in an object context, then you can use the magic method __call() to handle these types of requests so that you can route to private methods based on what arguments have been passed.
  8. 如果您正在使用对象上下文,则可以使用magic方法__call()来处理这些类型的请求,以便您可以根据传递的参数路由到私有方法。

#2


21  

A variation on the array technique that allows for easier setting of default values:

阵列技术的一种变体,可以更容易地设置默认值:

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

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

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

Usage:

用法:

foo(array('lastName' => 'smith')); // output: john smith

#3


9  

You could refactor your code slightly:

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

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

#4


6  

If you have multiple optional parameters, one solution is to pass a single parameter that is a hash-array:

如果您有多个可选参数,则一种解决方案是传递一个哈希数组的参数:

function foo(array $params = array()) {
    echo $params['firstName'] . " " . $params['lastName'];
}

foo(array('lastName'=>'smith'));

Of course in this solution there's no validation that the fields of the hash array are present, or spelled correctly. It's all up to you to validate.

当然,在此解决方案中,无法验证散列数组的字段是否存在或拼写正确。这完全由你来验证。

#5


3  

No. The usual way of doing this is with some heuristics to determine which parameter was implied, like string length, typing, etc.

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

Generally speaking, you'd write the function to take the parameters in the order of most required to least required.

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

#6


3  

The way you want: no.

你想要的方式:没有。

You could use some special mark, like NULL to note that value is not supplied:

你可以使用一些特殊的标记,比如NULL,注意不提供值:

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

foo(null, 'smith');

#7


1  

There are a few 'options' style implementations mentioned here. None thus far are very bulletproof if you plan to use them as as standard. Try this pattern:

这里提到了一些“选项”样式实现。如果你计划将它们作为标准使用,到目前为止都没有防水措施。试试这种模式:

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();
    }
}

This gives you function-local variables (just $foo in this example) and prevents creating any variables that do not have a default. This is so no one can accidentally overwrite other parameters or other variables within the function.

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

#8


1  

Arguments need to be passed in order by position, you cannot skip a parameter per se; you'll have to supply the default parameter value in order to skip it. Arguably that defeats the purpose of what you're trying to achieve.

参数需要按位置顺序传递,你不能跳过参数本身;你必须提供默认参数值才能跳过它。可以说,这打败了你想要实现的目标。

Without rewriting your function to accept parameters differently, here's a call-time way to work around this:

如果不重写您的函数以接受不同的参数,这里有一个调用时间方法来解决这个问题:

$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()));

In other words, you're using reflection to inspect the function's parameters and map them to the available parameters by name, skipping optional parameters with their default value. Yes, this is ugly and cumbersome. You could use this sample to create a function like:

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

call_func_with_args_by_name('foo', ['lastName' => 'Smith']);

#9


1  

I wish this solution had been on SO when I started using PHP 2.5 years ago. It works great in the examples I have created, and I don't see why it shouldn't be thoroughly extensible. It offers the following benefits over those proposed previously:

我希望这个解决方案在我2.5年前开始使用PHP时就已经存在了。它在我创建的示例中运行良好,我不明白为什么它不应该是完全可扩展的。它提供了以前提出的优点:

(i) all access to parameters within the function is by named variables, as if the parameters were fully declared, rather than requiring array access

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

(ii) it is very quick and easy to adapt existing functions

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

(iii) only a single line of additional code is required for any function (in addition to the inescapable necessity of defining your default parameters, which you would be doing in the function signature anyway, but instead you define them in an array). Credit for the additional line is wholly due to Bill Karwin. This line is identical for every function.

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

Method

方法

Define your function with its mandatory parameters, and an optional array

使用必需参数和可选数组定义函数

Declare your optional parameters as local variables

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

The crux: replace the pre-declared default value of any optional parameters using those you have passed via the array.

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

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

Call the function, passing its mandatory parameters, and only those optional parameters that you require

调用该函数,传递其必需参数,并仅传递您需要的可选参数

For example,

例如,

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";

}

and then call it like this

然后像这样调用它

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

Results:

结果:

The dog stood on the donkey

那只狗站在驴上

The cat sat on the donkey

那只猫坐在驴上

A dog stood on the mat

一条狗站在垫子上

#10


0  

If this is used very often, just define a new specialized function :

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

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

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

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

Note that you could also change the default value of $lastname in the process if you wish.

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

When a new function is estimated overbloated, just call you function with all parameters. If you want to make it more clear, you can prestore your literals in fin named variable or use comments.

当一个新函数被估计为overbloated时,只需使用所有参数调用函数。如果您想更清楚,可以在fin命名变量中预存文字或使用注释。

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

Ok, this is not as short and elegant as person($lastName='Lennon'), but it seems you can't have it in PHP. And that's not the sexiest way to code it, with super metaprogramming trick or whatever, but what solution would you prefer to encounter in a maintenance process?

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

#11


-1  

Sadly what you're trying to do has no "syntactic sugar" way of doing it. They're all varying forms of WTF.

可悲的是,你正在尝试做的事情没有“语法糖”的方式。它们都是各种形式的WTF。

If you need a function that takes an undefined number of arbitrary parameters,

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

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

Will do the trick. Try avoid using it too much, because for Php this is a bit on the magical side.

会做的伎俩。尽量避免使用太多,因为对于Php来说,这有点神奇。

You could then optionally apply defaults and do strange things based on parameter count.

然后,您可以选择应用默认值并根据参数计数执行奇怪的操作。

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];
}

Also, you could optionally emulate Perl style parameters,

此外,您可以选择模拟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' );

Of course, it would be easier to use an array argument here, but you're permitted to have choice ( even bad ways ) of doing things.

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

notedly, this is nicer in Perl because you can do just foo( firstname => 'john' );

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

#12


-1  

No there isn't but you could use an array:

没有,但你可以使用数组:

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

foo(array('lastName'=>'smith'));