在 PHP 中,是否可以像 Python 一样,在调用函数/方法时指定命名可选参数,跳过您不想指定的参数?
例如:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
在 PHP 中,是否可以像 Python 一样,在调用函数/方法时指定命名可选参数,跳过您不想指定的参数?
例如:
function foo($a, $b = '', $c = '') {
// whatever
}
foo("hello", $c="bar"); // we want $b as the default, but specify $c
PHP 8.0增加了对命名参数的支持,通过接受一个RFC来实现。
使用参数名称前缀加冒号将命名参数传递给函数。允许使用保留关键字作为参数名称。参数名称必须是标识符,不允许动态指定。
例如,在您的示例中仅传递第三个可选参数:
foo(timeout: 3);
在PHP 8之前,PHP不支持命名参数。实际上,当你调用foo($timeout=3)
时,它首先计算$timeout=3
,结果为3
,并将其作为第一个参数传递给foo()
。同时PHP强制参数顺序,因此相似的调用需要是foo("", "", $timeout=3)
。你有其他两个选项:
func_get_args()
获取PHP传入的参数或者在PHP 5.6+中使用...
可变长参数特性。根据参数数量,你可以决定如何处理每个参数。很多jQuery函数都采用这种方式。这是一种简单的方法,但对于调用你的函数的人来说可能会很困惑,因为它也不够自说明。而且你的参数仍然没有名称。foo( '', '', $timeout = 3 );
- user1115652foo('','',3/*timeout*/);
相比的优势是值得商榷的。 - user1115652...
解包关联数组(即 foo(...["timeout"=>3])
)也是一种选择。它可能在8.0之前就已经存在了,但我不确定。不知道是否值得一提。 - Joe Borisfunction foo($params) {
var_dump($params);
}
并以这种方式调用:(键/值数组)
foo([
'a' => 'hello',
]);
foo([
'a' => 'hello',
'c' => 'glop',
]);
foo([
'a' => 'hello',
'test' => 'another one',
]);
将会得到以下输出:
array
'a' => string 'hello' (length=5)
array
'a' => string 'hello' (length=5)
'c' => string 'glop' (length=4)
array
'a' => string 'hello' (length=5)
'test' => string 'another one' (length=11)
但我并不是很喜欢这个解决方案:
因此,我只会在非常特定的情况下使用它——例如对于有很多可选参数的函数...
PHP 8于2020年11月26日发布,带来了一个名为命名参数的新功能。
在这个重大版本发布中,"命名参数"(又称为"命名参数")为开发人员提供了一些非常酷的新技术,用于调用原生和自定义函数。
在这个问题中的自定义函数现在可以通过使用命名参数来调用第一个参数(因为它没有默认值),然后只传递第三个参数,就像这样:(演示)
function foo($a, $b = '', $c = '') {
echo $a . '&' . $b . '&' . $c;
}
foo("hello", c: "bar");
// output: hello&&bar
limit
参数、按照非正常顺序编写参数并声明引用变量的本地函数示例(Demo)。echo preg_replace(
subject: 'Hello 7',
pattern: '/[a-z ]/',
count: $counted,
replacement: ''
)
. " & " . $counted;
// output: H7 & 5
$params = [
'subject' => 'Hello 7', // normally third parameter
'pattern' => '/[a-z ]/', // normally first parameter
// 'limit' // normally fourth parameter, omitted for this demonstration; the default -1 will be used
'count' => &$counted, // normally fifth parameter
// ^-- don't forget to make it modifiable!
'replacement' => '', // normally second parameter
];
echo preg_replace(...$params) . " & " . $counted;
// same output as the previous snippet
call_user_func_array()
函数,可以享受相同的行为。使用我第一个声明的用户函数的演示。call_user_func_array('foo', ['c' => 9, 'a' => 7]);
// output: 7&&9
PHP并不直接支持命名参数。
在PHP中,你可以使用一个相当合理的替代方法。PHP的数组处理非常好,你可以使用关联数组来传递参数数组,如下所示:
function foo($parms=[]) {
$username = $parms['username'] ?? '…';
$password = $parms['password'] ?? '…';
$timeout = $parms['timeout'] ?? '…';
}
foo(['timeout'=>10]);
function foo($parms=[]) {
$username = '…';
$password = '…';
$timeout = '…';
extract($parms,EXTR_IF_EXISTS);
}
extract
函数将值复制到变量中,但只有在它们已经被定义的情况下才会执行。这样可以防止导入你不知道的变量。function foo($a = 10, $b = 20, $c = 30) {
return $a * $b - $c;
}
foo(a: 30, c: 10, b: 5);
foo(5, c: 60, b: 10);
foo(c: 30, b: 20, a: 10);
不可以,PHP不能通过名称传递参数。
如果你有一个需要很多参数并且它们都有默认值的函数,你可以考虑让该函数接受一个参数数组:
function test (array $args) {
$defaults = array('a' => '', 'b' => '', 'c' => '');
$args = array_merge($defaults, array_intersect_key($args, $defaults));
list($a, $b, $c) = array_values($args);
// an alternative to list(): extract($args);
// you can now use $a, $b, $c
}
在 PHP 7.* 或更低版本中不支持命名参数。
但是它将在 PHP 8 中实现 https://wiki.php.net/rfc/named_params
RFC 已经获得批准。 命名参数将在 PHP 8 中被实现。
您可以通过传递一个对象而不是数组来保留phpdoc和设置默认值的能力,例如:
class FooOptions {
$opt1 = 'x';
$opt2 = 'y';
/* etc */
};
如果您想要,在函数调用中也可以进行严格的类型检查:
function foo (FooOptions $opts) {
...
}
bar('one', ['a1' => 'two', 'bar' => 'three', 'foo' => 'four']);
// output: twothreefour
function bar ($a1, $kwargs = ['bar' => null, 'foo' => null]) {
extract($kwargs);
echo $a1;
echo $bar;
echo $foo;
}
bar('one', ['x' => 'blah']);
,$bar
不是未定义吗?即使在这种情况下,extract()
似乎是危险和不必要的... - binkiextract()
函数无法填充所需的变量到作用域中。https://3v4l.org/UdkAq - mickmackusa
$c="bar"
将bar
赋值给了调用者作用域中的$c
(而不是在被调用的函数foo
中),然后将分配的值作为第二个参数传递给foo()
,这将作为本地$b
变量接收。 - Petruza