在PHP中,参数列表是传递信息到函数的桥梁,它是由逗号分隔的一系列表达式。在函数被实际调用之前,值参数会按照从左向右的顺序进行求值(也称为早期求值)。
PHP 支持按值传递参数(默认),通过引用传递参数以及默认参数,也支持可变长度参数列表和命名参数。
1、向函数传递数组:
<?<a href="https://www.zzbaike.com/tag/php" title="查看所有文章关于 php" target="_blank">php</a>
function takes_array($input)
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
<?<a href="https://www.zzbaike.com/tag/php" title="查看所有文章关于 php" target="_blank">php</a>
function takes_array($input)
{
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
<?php
function takes_array($input)
{
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
从 PHP 8.0.0 开始,函数参数列表可以包含一个尾部的逗号。这个逗号在语法上是可选的,但在实际使用中会被忽略。这在参数列表较长或包含较长的变量名的情况下特别有用,因为它允许垂直列出参数,使代码更易于阅读和理解。
2、函数参数使用尾部逗号:
function takes_many_args(
$a_very_long_argument_name,
$again = 'a default string', // 在 8.0.0 之前,这个尾部的逗号是不允许的。
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // 在 8.0.0 之前,这个尾部的逗号是不允许的。
)
{
// ...
}
?>
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // 在 8.0.0 之前,这个尾部的逗号是不允许的。
)
{
// ...
}
?>
一、通过引用传递参数
默认情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,它并不会改变函数外部的值)。如果希望允许函数修改它的参数值,必须通过引用传递参数。如果想要函数的一个参数总是通过引用传递,可以在函数定义中该参数的前面加上符号 &。
用引用传递函数参数:
function add_some_extra(&$string)
$string .= 'and something extra.';
$str = 'This is a string, ';
echo $str; // 输出 'This is a string, and something extra.'
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // 输出 'This is a string, and something extra.'
?>
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // 输出 'This is a string, and something extra.'
?>
二、默认参数值
PHP 函数可以使用类似分配变量的语法为函数参数定义默认值,当调用函数时,如果没有为该参数提供值,那么将使用默认值。需要注意的是,传递 null 不会分配默认值。
1、在函数中使用默认参数:
function makecoffee($type = "cappuccino")
return "Making a cup of $type.\n";
echo makecoffee("espresso");
<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>
<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>
以上示例会输出:
Making a cup of cappuccino.
Making a cup of espresso.
Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.
Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.
函数参数的默认值可以是标量值、数组、特殊类型 null,以及从 PHP 8.1.0 开始,使用 new ClassName() 语法的对象。
2、使用非标量类型作为默认参数:
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
echo makecoffee(array("cappuccino", "lavazza"), "teapot");?>
<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");?>
<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");?>
3、使用对象作为默认值(自 PHP 8.1.0 起):
class DefaultCoffeeMaker {
return 'Crafting a beautiful coffee just for you.';
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
return $coffeeMaker->brew();
echo makecoffee(new FancyCoffeeMaker);
<?php
class DefaultCoffeeMaker {
public function brew() {
return 'Making coffee.';
}
}
class FancyCoffeeMaker {
public function brew() {
return 'Crafting a beautiful coffee just for you.';
}
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);
?>
<?php
class DefaultCoffeeMaker {
public function brew() {
return 'Making coffee.';
}
}
class FancyCoffeeMaker {
public function brew() {
return 'Crafting a beautiful coffee just for you.';
}
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);
?>
默认值必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。注意任何可选参数都应在强制参数之后指定,否则可选参数不能在调用时省略。考虑以下示例:
4、函数默认参数的不正确用法:
function makeyogurt($container = "bowl", $flavour)
return "Making a $container of $flavour yogurt.\n";
echo makeyogurt("raspberry"); // "raspberry" 是 $container, 不是 $flavour
<?php
function makeyogurt($container = "bowl", $flavour)
{
return "Making a $container of $flavour yogurt.\n";
}
echo makeyogurt("raspberry"); // "raspberry" 是 $container, 不是 $flavour
?>
<?php
function makeyogurt($container = "bowl", $flavour)
{
return "Making a $container of $flavour yogurt.\n";
}
echo makeyogurt("raspberry"); // "raspberry" 是 $container, 不是 $flavour
?>
以上示例会输出:
Fatal error: Uncaught ArgumentCountError: Too few arguments
to function makeyogurt(), 1 passed in example.php on line 42
Fatal error: Uncaught ArgumentCountError: Too few arguments
to function makeyogurt(), 1 passed in example.php on line 42
Fatal error: Uncaught ArgumentCountError: Too few arguments
to function makeyogurt(), 1 passed in example.php on line 42
比较上面的例子和这个例子:
5、函数默认参数正确的用法:
function makeyogurt($flavour, $container = "bowl")
return "Making a $container of $flavour yogurt.\n";
echo makeyogurt("raspberry"); // "raspberry" 是 $flavour
<?php
function makeyogurt($flavour, $container = "bowl")
{
return "Making a $container of $flavour yogurt.\n";
}
echo makeyogurt("raspberry"); // "raspberry" 是 $flavour
?>
<?php
function makeyogurt($flavour, $container = "bowl")
{
return "Making a $container of $flavour yogurt.\n";
}
echo makeyogurt("raspberry"); // "raspberry" 是 $flavour
?>
以上示例会输出:
Making a bowl of raspberry yogurt.
Making a bowl of raspberry yogurt.
Making a bowl of raspberry yogurt.
自 PHP 8.0.0 起,命名参数可用于跳过多个可选参数。
6、函数默认参数正确的用法:
function makeyogurt($container = "bowl", $flavour = "raspberry", $style = "Greek")
return "Making a $container of $flavour $style yogurt.\n";
echo makeyogurt(style: "natural");
<?php
function makeyogurt($container = "bowl", $flavour = "raspberry", $style = "Greek")
{
return "Making a $container of $flavour $style yogurt.\n";
}
echo makeyogurt(style: "natural");
?>
<?php
function makeyogurt($container = "bowl", $flavour = "raspberry", $style = "Greek")
{
return "Making a $container of $flavour $style yogurt.\n";
}
echo makeyogurt(style: "natural");
?>
以上示例会输出:
Making a bowl of raspberry natural yogurt.
Making a bowl of raspberry natural yogurt.
Making a bowl of raspberry natural yogurt.
从 PHP 8.0.0 开始,不再支持在可选参数之后声明强制参数。这通常可以通过删除默认值来解决,因为该默认值永远不会被使用。唯一的例外是 Type $param = null 类型的参数,其中默认值为 null 可以使得该类型隐式为 null。这种做法仍然可以使用,但是推荐使用显式可为 null 类型代替。
7、强制参数后声明可选参数:
function foo($a = [], $b) {} // 默认不使用;自 PHP 8.0.0 起弃用
function foo($a, $b) {} // 功能相同,无弃用通知
function bar(A $a = null, $b) {} // 仍然允许;但 $a 强制但可以为 null
function bar(?A $a, $b) {} // 推荐
<?php
function foo($a = [], $b) {} // 默认不使用;自 PHP 8.0.0 起弃用
function foo($a, $b) {} // 功能相同,无弃用通知
function bar(A $a = null, $b) {} // 仍然允许;但 $a 强制但可以为 null
function bar(?A $a, $b) {} // 推荐
?>
<?php
function foo($a = [], $b) {} // 默认不使用;自 PHP 8.0.0 起弃用
function foo($a, $b) {} // 功能相同,无弃用通知
function bar(A $a = null, $b) {} // 仍然允许;但 $a 强制但可以为 null
function bar(?A $a, $b) {} // 推荐
?>
注意:
- 自 PHP 7.1.0 起,省略未指定默认值的参数会原因引发 ArgumentCountError;在此之前的版本会引发警告。
- 传引用的参数也可以有默认值。
三、可变数量参数列表
PHP 允许在用户自定义函数中使用可变数量的参数列表,这可以通过使用 … 语法来实现。除了使用 … 语法外,还可以使用以下函数来获取可变参数:func_num_args()、func_get_arg() 和 func_get_args()。但是,建议使用 … 语法来替代这些函数,因为它们更加简洁明了。
包含 … 的参数,会转换为指定参数变量的一个 array:
1、使用 … 来访问变量参数:
function sum(...$numbers) {
foreach ($numbers as $n) {
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
以上示例会输出:
10
也可以使用 … 语法来传递 array 或 Traversable 做为参数到函数中:
2、使用 … 来传递参数:
echo add(...[1, 2])."\n";
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
以上示例会输出:
3
3
在 PHP 中,可以使用 … 语法来获取可变数量的参数。在这种情况下,只有不符合位置参数的尾部参数才会被添加到由 … 生成的数组中。此外,还可以在 … 标记前添加一个类型声明,以确保捕获的所有参数都与参数类型匹配。
3、输入提示的变量参数:
function total_intervals($unit, DateInterval ...$intervals) {
foreach ($intervals as $interval) {
$time += $interval->$unit;
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// 这将会失败,因为 null 不是 DateInterval 对象。
echo total_intervals('d', null);
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// 这将会失败,因为 null 不是 DateInterval 对象。
echo total_intervals('d', null);
?>
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// 这将会失败,因为 null 不是 DateInterval 对象。
echo total_intervals('d', null);
?>
以上示例会输出:
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
最后还可以给参数传递 引用变量,通过在 … 前加上一个 (&) 符号来实现。
四、旧版本的PHP
不需要特殊的语法来声明一个函数是可变的;但是访问函数的参数必须使用 func_num_args(), func_get_arg() 和 func_get_args() 函数。
上面的第一个例子在早期 PHP 版本中的实现如下:
在 PHP 早期版本中访问可变参数:
foreach (func_get_args() as $n) {
<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
以上示例会输出:
10
五、命名参数
从 PHP 8.0.0 开始,引入了命名参数作为现有位置参数的扩展。命名参数允许根据参数名而不是参数位置向函数传参。这使得参数的含义自成体系,参数与顺序无关,并允许任意跳过默认值。命名参数通过在参数名前加上冒号来传递。允许使用保留关键字作为参数名。参数名必须是一个标识符,不允许动态指定。
1、命名参数的语法:
myFunction(paramName: $value);
array_foobar(array: $value);
function_name($variableStoringParamName: $value);
<?php
myFunction(paramName: $value);
array_foobar(array: $value);
// 不支持。
function_name($variableStoringParamName: $value);
?>
<?php
myFunction(paramName: $value);
array_foobar(array: $value);
// 不支持。
function_name($variableStoringParamName: $value);
?>
2、通过位置传参与命名参数的对比:
array_fill(start_index: 0, count: 100, value: 50);
<?php
// 使用顺序传递参数:
array_fill(0, 100, 50);
// 使用命名参数:
array_fill(start_index: 0, count: 100, value: 50);
?>
<?php
// 使用顺序传递参数:
array_fill(0, 100, 50);
// 使用命名参数:
array_fill(start_index: 0, count: 100, value: 50);
?>
指定参数的传递顺序并不重要。
3、参数顺序不同的示例(同上例):
array_fill(value: 50, count: 100, start_index: 0);
<?php
array_fill(value: 50, count: 100, start_index: 0);
?>
<?php
array_fill(value: 50, count: 100, start_index: 0);
?>
命名参数也可以与位置参数相结合使用,这种情况下,命名参数必须在位置参数之后。此外,还可以只指定一个函数的部分可选参数,而不考虑它们的顺序。
4、命名参数与位置参数结合使用:
htmlspecialchars($string, double_encode: false);
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
<?php
htmlspecialchars($string, double_encode: false);
// 等价于
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>
<?php
htmlspecialchars($string, double_encode: false);
// 等价于
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>
传递多个相同参数将会导致 Error 异常。
5、传递多个相同参数将会导致抛出 Error:
function foo($param) { ... }
// 错误:命名参数 $param 覆盖了之前的参数
// 错误:命名参数 $param 覆盖了之前的参数
<?php
function foo($param) { ... }
foo(param: 1, param: 2);
// 错误:命名参数 $param 覆盖了之前的参数
foo(1, param: 2);
// 错误:命名参数 $param 覆盖了之前的参数
?>
<?php
function foo($param) { ... }
foo(param: 1, param: 2);
// 错误:命名参数 $param 覆盖了之前的参数
foo(1, param: 2);
// 错误:命名参数 $param 覆盖了之前的参数
?>
自 PHP 8.1.0 起,可以在解包参数后面使用命名参数。命名参数不能覆盖已解包的参数。
6、解包后使用命名参数:
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
var_dump(foo(...[1, 2], b: 20)); // Fatal error。命名参数 $b 覆盖之前的参数
<?php
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
}
var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
var_dump(foo(...[1, 2], b: 20)); // Fatal error。命名参数 $b 覆盖之前的参数
?>
<?php
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
}
var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
var_dump(foo(...[1, 2], b: 20)); // Fatal error。命名参数 $b 覆盖之前的参数
?>