函数参数

可以通过参数列表(逗号分隔的表达式列表)向函数传递信息。在实际调用函数之前(热切求值),从左到右计算参数。

PHP 支持通过值(默认)、通过引用默认参数值传递参数。还支持 可变长度参数列表命名参数

示例 #1 将数组传递到函数

<?php
function takes_array($input)
{
echo
"$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>

从 PHP 8.0.0 开始,函数参数列表可以包含尾部逗号,该逗号将被忽略。在参数列表较长或包含冗长变量名的情况下,这样做特别有用,因为这样可以方便地垂直列出参数。

示例 #2 带尾部逗号的函数参数列表

<?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 之前,不允许使用此尾部逗号。
)
{
// ...
}
?>

通过引用传递参数

默认情况下,函数参数按值传递(因此,如果函数中参数的值发生更改,它将不会在函数外部发生更改)。要允许函数修改其参数,必须通过引用传递参数。

要使传递给函数的参数始终通过引用传递,请在函数定义中在参数名前面加上一个 & 符号

例 3 通过引用传递函数参数

<?php
function add_some_extra(&$string)
{
$string .= '以及其他一些东西.';
}
$str = '这是一个字符串, ';
add_some_extra($str);
echo
$str; // 输出'这是一个字符串,以及其他一些东西.'

将应该是通过引用方式传递的值作为参数进行传递是一种错误做法。

默认参数的值

一个函数可以通过使用类似于给变量赋值的语法来定义参数的默认值。默认值仅在参数未指定的情况下才使用;特别地,请注意传递null 不会分配默认值。

示例 #4 在函数中使用默认参数

<?php
function makecoffee($type = "cappuccino")
{
return
"准备一杯 $type.\n";
}
echo
makecoffee();
echo
makecoffee(null);
echo
makecoffee("espresso");
?>

上述示例将输出

Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.

默认参数值可以是标量值、数组、特殊类型null,以及从 PHP 8.1.0 起,使用 new ClassName() 语法的对象。

示例 #5 使用非标量类型作为默认值

<?php
函数 makecoffee($types = 数组("卡布奇诺"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "手" : $coffeeMaker;
return
"用 $device做一杯 ".join(", ", $types)."。\\n";
}
echo
makecoffee();
echo
makecoffee(数组("卡布奇诺", "拿铁"), "茶壶");?>

上述示例将输出

Making a cup of cappuccino with hands.
Making a cup of cappuccino, lavazza with teapot.

示例 6 使用对象作为默认值(来自 PHP 8.1.0)

<?php
DefaultCoffeeMaker {
public 函数
brew() {
return
"制作咖啡。\\n";
}
}
FancyCoffeeMaker {
public 函数
brew() {
return
"只为你制作一杯美味的咖啡。\\n";
}
}
函数
makecoffee($coffeeMaker = 新 DefaultCoffeeMaker)
{
return
$coffeeMaker->brew();
}
echo
makecoffee();
echo
makecoffee(新 FancyCoffeeMaker);
?>

上述示例将输出

Making coffee.
Crafting a beautiful coffee just for you.

默认值必须是常量表达式,而不是(例如)变量、类成员或函数调用。

请注意,任何可选参数都应当在任何必需参数之后指定,否则就不能从调用中省略它们。考虑以下示例

示例 7 默认函数参数使用不当

<?php
函数 makeyogurt($container = "碗", $flavor)
{
返回
"制作一 $container$flavor 酸奶。\n";
}

echo
makeyogurt("树莓"); // "树莓"是 $container,不是 $flavor
?>

上述示例将输出

Fatal error: Uncaught ArgumentCountError: Too few arguments
 to function makeyogurt(), 1 passed in example.php on line 42

现在,将以上内容与此进行比较

示例 #8 正确使用默认函数参数

<?php
函数 makeyogurt($flavor, $container = "碗")
{
返回
"制作一 $container$flavor 酸奶。\n";
}

echo
makeyogurt("树莓"); // "tree" is $flavor
?>

上述示例将输出

Making a bowl of raspberry yogurt.

在 PHP 8.0.0 中,已命名的参数可用于跳过多个可选参数。

示例 #9 正确使用默认函数参数

<?php
函数 makeyogurt($container = "碗", $flavor = "树莓", $style = "希腊")
{
返回
"制作一 $container$flavor $style 酸奶。\n";
}

echo
makeyogurt(style: "天然");
?>

上述示例将输出

Making a bowl of raspberry natural yogurt.

自 PHP 8.0.0 起,在可选项之后声明必选项将被弃用。可以通过删掉默认值解决这个问题,因为它永远不会被用到。这个规则有一个例外,即 类型 $param = null 格式的参数,使用null 默认值让类型隐式可空。这种用法仍然允许,尽管建议使用明确的 可空类型

示例 #10 在必选项之后声明可选项

<?php
函数 foo($a = [], $b) {} // 默认值不会被使用;自 PHP 8.0.0 起弃用
函数 foo($a, $b) {} // 功能上等价,没有弃用通知

函数 bar(A $a = null, $b) {} // 仍允许;$a 为必需项,但可空
函数 bar(?A $a, $b) {} // 建议
?>

注意: 自 PHP 7.1.0 起,省略未指定默认值的参数会抛出 ArgumentCountError;在之前的版本中,它会引发警告。

注意: 通过引用传递的参数可以有默认值。

可变长度参数列表

PHP 通过使用 ... 令牌在用户定义的函数中支持可变长度参数列表。

参数列表中可以包含 ... 令牌,表示函数接受可变数量的参数。参数将作为 数组 传递到给定的变量中

示例 #11 使用 ... 访问可变参数

<?php
函数 求和(...$数字) {
$累加 = 0;
foreach (
$数字 as $n) {
$累加 += $n;
}
返回
$累加;
}
echo
求和(1, 2, 3, 4);
?>

上述示例将输出

10

... 也可以在调用函数以将 数组Traversable 变量或字面量解包到参数列表中时使用

示例 #12 使用 ... 提供参数

<?php
函数 加法($a, $b) {
返回
$a +$b;
}
echo
加法(...[1, 2])."\n";

$a = [1, 2];
echo
加法(...$a);
?>

上述示例将输出

3
3

你可以在 ... 令牌之前指定常规位置参数。在这种情况下,只有不匹配位置参数的尾随参数才会被添加到由 ... 生成得数组中。

... 令牌之前添加 类型声明 也是可能的。如果存在,那么 ... 捕获的所有参数都必须匹配该参数类型。

示例 #13 类型声明的变量参数

<?php
函数 total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
遍历 (
$intervals $interval) {
$time += $interval->$unit;
}
返回
$time;
}

$a = 新 DateInterval('P1D');
$b = 新 DateInterval('P2D');
echo
total_intervals('d', $a, $b).' 天';

// 这将失败,因为 null 不是 DateInterval 对象。
echo total_intervals('d', null);
?>

上述示例将输出

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 8.0.0 引入了命名参数作为现有位置参数的扩展。命名参数允许根据参数名称(而不是参数位置)向函数传递参数。这使参数的含义不言自明,使参数顺序无关,并允许任意跳过默认值。

命名参数通过在值前加上冒号后跟参数名称来传递。允许使用保留关键字作为参数名称。参数名称必须是标识符,不允许动态指定。

示例 #14 命名参数语法

<?php
myFunction
(paramName: $value);
array_foobar(array: $value);

// 不支持。
function_name($variableStoringParamName: $value);
?>

例 15 指定位置自变量与指定名称自变量

<?php
// 使用指定位置的自变量:
array_fill(0, 100, 50);

// 使用指定名称的自变量:
array_fill(start_index: 0, count: 100, value: 50);
?>

传递指定名称的自变量时,其顺序无关紧要。

例 16 上面示例中,使用不同顺序的参数表示

<?php
array_fill
(value: 50, count: 100, start_index: 0);
?>

指定名称的自变量可以与指定位置的自变量合并。在这种情况下,指定名称的自变量必须在指定位置自变量之后。还可以仅指定某个函数的某些可选自变量,而不管其顺序如何。

例 17 将指定名称的自变量与指定位置的自变量合并

<?php
htmlspecialchars
($string, double_encode: false);
// 等效于
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>

多次传递相同参数会引发 Error 异常。

示例 #18 多次传递相同参数时抛出错误

<?php
function foo($param) { ... }

foo(param: 1, param: 2);
// 错误:命名参数 $param 覆盖前面的参数
foo(1, param: 2);
// 错误:命名参数 $param 覆盖前面的参数
?>

从 PHP 8.1.0 开始,可以在解包参数后使用命名参数。一个命名参数不得覆盖一个已解包的参数。

示例 #19 在解包后使用命名参数

<?php
函数 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)); // 致命错误。命名参数 $b 覆盖前面的参数
?>
add a note

用户贡献的备注 15 个备注

up
128
php at richardneill dot org
9 年前
为了评估传引用的性能和传值的性能,我使用了此脚本。以下是结论。

#!/usr/bin/php
<?php
function sum($array,$max){ //For Reference, use: "&$array"
$sum=0;
for (
$i=0; $i<2; $i++){
#$array[$i]++; //Uncomment this line to modify the array within the function.
$sum += $array[$i];
}
return (
$sum);
}

$max = 1E7 //10 M data points.
$data = range(0,$max,1);

$start = microtime(true);
for (
$x = 0 ; $x < 100; $x++){
$sum = sum($data, $max);
}
$end = microtime(true);
echo
"Time: ".($end - $start)." s\n";

/* Run times:
# PASS BY MODIFIED? Time
- ------- --------- ----
1 value no 56 us
2 reference no 58 us

3 valuue yes 129 s
4 reference yes 66 us

Conclusions:

1. PHP is already smart about zero-copy / copy-on-write. A function call does NOT copy the data unless it needs to; the data is
only copied on write. That's why #1 and #2 take similar times, whereas #3 takes 2 million times longer than #4.
[You never need to use &$array to ask the compiler to do a zero-copy optimisation; it can work that out for itself.]

2. You do use &$array to tell the compiler "it is OK for the function to over-write my argument in place, I don't need the original
any more." This can make a huge difference to performance when we have large amounts of memory to copy.
(This is the only way it is done in C, arrays are always passed as pointers)

3. The other use of & is as a way to specify where data should be *returned*. (e.g. as used by exec() ).
(This is a C-like way of passing pointers for outputs, whereas PHP functions normally return complex types, or multiple answers
in an array)

4. It's unhelpful that only the function definition has &. The caller should have it, at least as syntactic sugar. Otherwise
it leads to unreadable code: because the person reading the function call doesn't expect it to pass by reference. At the moment,
it's necessary to write a by-reference function call with a comment, thus:
$sum = sum($data,$max); //warning, $data passed by reference, and may be modified.

5. Sometimes, pass by reference could be at the choice of the caller, NOT the function definitition. PHP doesn't allow it, but it
would be meaningful for the caller to decide to pass data in as a reference. i.e. "I'm done with the variable, it's OK to stomp
on it in memory".
*/
?>
up
11
Simmo at 9000 dot 000
2 年前
对于刚开始接触 PHP 或搜索的人员,对于此页所述内容(即变长参数中的“令牌”),可以理解如下:
https://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
<?php

func
($a, ...$b)

?>
三个点号或省略号或“...”或点号点号有时在其他语言中被称为“展开运算符”。

由于这仅用于函数参数,因此在 PHP 中可能从技术上来说不是真正的运算符。(至少在 8.1 版中是这样?)

(因为难以搜索名称“...”的名称,我希望此注释对某人有所帮助)。
up
19
LilyWhite
2 年前
值得注意的是,你可以将函数用作函数参数

<?php
function run($op, $a, $b) {
return
$op($a, $b);
}

$add = function($a, $b) {
return
$a + $b;
};

$mul = function($a, $b) {
return
$a * $b;
};

echo
run($add, 1, 2), "\n";
echo
run($mul, 1, 2);
?>

输出
3
2
up
17
Hayley Watson
6 年前
使用 ... 向函数调用提供多个参数的限制比在函数声明中使用它声明不定参数时的限制更少。具体而言,可以使用它多次来解压缩参数,前提是所有这些使用都出现在任何位置参数之后。

<?php

$array1
= [[1],[2],[3]];
$array2 = [4];
$array3 = [[5],[6],[7]];

$result = array_merge(...$array1); // Legal, of course: $result == [1,2,3];
$result = array_merge($array2, ...$array1); // $result == [4,1,2,3]
$result = array_merge(...$array1, $array2); // Fatal error: Cannot use positional argument after argument unpacking.
$result = array_merge(...$array1, ...$array3); // Legal! $result == [1,2,3,5,6,7]
?>

对于以上错误,正确的做法是让 $result==[1,2,3,4],但这尚未(v7.1.8)支持。
up
30
gabriel at figdice dot org
8 年前
函数的一个参数是一个对象,它的属性将由函数修改,即使你不必按引用传递它。

<?php
$x
= new stdClass();
$x->prop = 1;

function
f ( $o ) // 请注意没有 &
{
$o->prop ++;
}

f($x);

echo
$x->prop; // 显示:2
?>

对于数组则不同

<?php
$y
= [ 'prop' => 1 ];

function
g( $a )
{
$a['prop'] ++;
echo
$a['prop']; // shows: 2
}

g($y);

echo
$y['prop']; // shows: 1
?>
up
14
boan dot web at outlook dot com
6 年前
引用

“如果参数的默认值设置为 NULL,则可以对声明进行更改以接受 NULL 值”。

但你可以这样做(PHP 7.1+)

<?php
function foo(?string $bar) {
//...
}

foo(); // Fatal error
foo(null); // Okay
foo('Hello world'); // Okay
?>
up
13
jcaplan at bogus dot amazon dot com
18 年前
在函数调用中,PHP 明显区分了缺失参数和存在但为空的参数。因此

<?php
function f( $x = 4 ) { echo $x . "\\n"; }
f(); // prints 4
f( null ); // prints blank line
f( $y ); // $y undefined, prints blank line
?>

因此,可选参数特性的实用性有所降低。假设您想从函数 g 多次调用函数 f,从而允许 g 的调用者指定是否使用特定值还是使用默认值来调用 f

<?php
函数 f( $x = 4 ) {echo $x . "\\n"; }

// 选项 1:剪切并粘贴 f 的界面中的默认值到 g 中
函数 g( $x = 4 ) { f( $x ); f( $x ); }

// 选项 2:根据 g 的输入进行分支
函数 g( $x = null ) { if ( !isset( $x ) ) { f(); f() } else { f( $x ); f( $x ); } }
?>

两种选择都不好。

在我看来,最好的方法是始终将 Sentinel(如 null)用作可选参数的默认值。这样,调用方(如 g 及 g 的客户端)有许多选择,此外,调用方始终知道如何省略参数,以便它们可以在参数列表中间省略一个参数。

<?php
函数 f( $x = null ) { 如果 ( !isset( $x ) ) $x = 4; 回显 $x . "\\n"; }

函数
g( $x = null ) { f( $x ); f( $x ); }

f(); // 打印 4
f( null ); // 打印 4
f( $y ); // $y 未定义,打印 4
g(); // 打印 4 两次
g( null ); // 打印 4 两次
g( 5 ); // 打印 5 两次

?>
up
13
Sergio Santana: ssantana 在 tlaloc 点 imta 点 mx
18 年前
将一个“可变长度参数引用列表”传递给函数
从 PHP 5 开始,按引用调用已经弃用,这在大多数情况下没有问题,因为你可以像这样调用一个函数,而不是像这样
myfunction($arg1, &$arg2, &$arg3);

你可以调用它
myfunction($arg1, $arg2, $arg3);

前提是你已经将函数定义为
function myfuncion($a1, &$a2, &$a3) { // 因此 &$a2 和 &$a3 被
// 声明为引用。
... <function-code>
}

但是,如果你想传递一个未定义数量的引用,即类似于
myfunction(&$arg1, &$arg2, ..., &$arg-n);?
这在 PHP 5 中不再起作用。

在 folgenden 代码中,我尝试使用
array() 语言结构作为
调用函数中的实际参数来修正这个问题。

<?php

函数 aa ($A) {
// 此函数将每个
// "伪参数" 增大 2
foreach ($A as &$x) {
$x += 2;
}
}

$x = 1; $y = 2; $z = 3;

aa(array(&$x, &$y, &$z));
echo
"--$x--$y--$z--\n";
// 它会输出:
// --3--4--5--
?>

希望这个对你有所帮助。

Sergio。
up
2
tianyiw at vip dot qq dot com
1 年前
<?php
/**
* 使用命名参数创建数组。
*
* @param mixed ...$values
* @return array
*/
function arr(mixed ...$values): array
{
return
$values;
}

$arr = arr( name: 'php',
mobile: 123456,
);

var_dump($arr);
// array(2) {
// ["name"]=>
// string(3) "php"
// ["mobile"]=>
// int(123456)
// }
up
3
Luna
1 年前
使用命名参数并将默认值只添加到一些参数时,带默认值的这些参数必须指定在末尾,否则 PHP 将引发错误

<?php

function test1($a, $c, $b = 2)
{
return
$a + $b + $c;
}
function
test2($a, $b = 2, $c)
{
return
$a + $b + $c;
}

echo
test1(a: 1, c: 3)."\n"; // 有效
echo test2(a: 1, c: 3)."\n"; // ArgumentCountError: 未传递参数 2 ($b)

?>

我猜想,这是因为在内部 PHP 会将调用重写为类似于 test1(1, 3) 和 test2(1, , 3) 的内容。第一个调用有效,但第二个显然无效。
up
5
catman at esteticas dot se
8 年前
我想知道可变长参数列表和引用是否可以一起工作,以及语法可能是什么。据我所知,PHP 手册中尚未明确提及这一点。但其他来源提到了适用于 PHP 5.6.16 的语法 "&...$variable"。

<?php
function foo(&...$args)
{
$i = 0;
foreach (
$args as &$arg) {
$arg = ++$i;
}
}
foo($a, $b, $c);
echo
'a = ', $a, ', b = ', $b, ', c = ', $c;
?>
给出
a = 1, b = 2, c = 3
up
5
海莉·沃森
6 年前
如果你在函数的参数列表中使用 ...,那么由于显而易见的原因,你只能用一次。不太显而易见的是,它必须用在最后一个参数中;正如手册中所说的:“可以在 ... 令牌之前指定常规位置参数。(强调是我的)”。

<?php
function 可变参数($first, ...$most, $last)
{
/*等*/}

可变参数(1, 2, 3, 4, 5);
?>
导致致命错误,即使它看起来像“要做的事”将 $first 设置为 1,将 $most 设置为 [2, 3, 4],并将 $last 设置为 5。
up
1
[email protected]
6 年前
你可以使用类常量作为默认参数。

<?php

class A {
const
FOO = '默认';
function
bar( $val = self::FOO ) {
echo
$val;
}
}

$a = new A();
$a->bar(); // 将回显“默认”
up
1
海莉·沃森
2 个月前
... 参数语法将捕获与实际函数参数不对应的命名参数。这些未知的命名参数将被 func_get_args() 等函数忽略,但它们在可变参数中以给定它们的名称提供。

<?php

函数 demo($first, $second, ...$rest)
{
echo
"First:";
var_dump($first);
echo
"\n";

echo
"Second:";
var_dump($second);
echo
"\n";

echo
"Rest:";
var_dump($rest);
echo
"\n";
}

demo(1, third:3, second:2, fourth:4);
?>
up
0
John
17 年前
该处可能在某个地方已记录在案,或者对大多数人显而易见,但通过引用传递一个参数(即 PHP 5.04),可以在函数调用中为一个参数变量分配一个值。例如

function my_function($arg1, &$arg2) {
if ($arg1 == true) {
$arg2 = true;
}
}
my_function(true, $arg2 = false);
echo $arg2;

输出 1 (true)

my_function(false, $arg2 = false);
echo $arg2;

输出 0 (false)
To Top