## 函数的参数
通过参数列表可以传递信息到函数,即以逗号作为分隔符的表达式列表。参数是从左向右求值的。PHP 支持按值传递参数(默认),[通过引用传递参数](http://php.net/manual/zh/functions.arguments.php#functions.arguments.by-reference)以及[默认参数](http://php.net/manual/zh/functions.arguments.php#functions.arguments.default)。也支持[可变长度参数列表](http://php.net/manual/zh/functions.arguments.php#functions.variable-arg-list)。
**Example #1 向函数传递数组**
```
<?php
function takes_array($input)
{
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
```
## 通过引用传递参数
默认情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,他并不会改变函数外部的值)。如果希望允许函数修改它的 参数值,必须通过引用传递参数。
如果想要函数的一个参数总是通过引用传递,可以在函数定义中该参数的前面加上符号&:
**Example #2 用引用传递函数参数**
```
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // outputs 'This is a string, and something extra.'
?>
```
### 默认参数的值
函数可以定义 C++ 风格的标量参数默认值,如下所示:
**Example #3 在函数中使用默认参数**
```
<?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 .
Making a cup of espresso.
~~~
PHP 还允许使用数组 [array](http://php.net/manual/zh/language.types.array.php) 和特殊类型 **`NULL`** 作为默认参数,例如:
**Example #4 使用非标量类型作为默认参数**
```
<?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");
?>
```
默认值必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。
注意当使用默认参数时,任何默认参数必须放在任何非默认参数的右侧;否则,函数将不会按照预期的情况工作。考虑下面的代码片断:
**Example #5 函数默认参数的不正确用法**
```
<?php
function makeyogurt($type = "acidophilus", $flavour)
{
return "Making a bowl of $type$flavour.\n";
}
echo makeyogurt("raspberry"); // won't work as expected
?>
```
以上例程会输出:
~~~
Warning: Missing argument 2 in call to makeyogurt() in
/usr/local/etc/httpd/htdocs/phptest/functest.html on line 41
Making a bowl of raspberry .
~~~
现在,比较上面的例子和这个例子:
**Example #6 函数默认参数正确的用法**
```
<?php
function makeyogurt($flavour, $type = "acidophilus")
{
return "Making a bowl of $type$flavour.\n";
}
echo makeyogurt("raspberry"); // works as expected
?>
```
以上例程会输出:
~~~
Making a bowl of acidophilus raspberry.
~~~
> **Note**: 自 PHP 5 起,传引用的参数也可以有默认值。
### 类型声明
> **Note**:
>
> 在PHP 5中,类型声明也被称为类型提示。
类型声明允许函数在调用时要求参数为特定类型。 如果给出的值类型不对,那么将会产生一个错误: 在PHP 5中,这将是一个可恢复的致命错误,而在PHP 7中将会抛出一个**TypeError**异常。
为了指定一个类型声明,类型应该加到参数名前。这个声明可以通过将参数的默认值设为**`NULL`**来实现允许传递**`NULL`**。
#### 范例
**Example #7 Basic class type declaration**
`<?php
class C {}
class D extends C {}
// This doesn't extend C.
class E {}
function f(C $c) {
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>`
以上例程会输出:
~~~
C
D
Fatal error: Uncaught TypeError: Argument 1 passed to f() must be an instance of C, instance of E given, called in - on line 14 and defined in -:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
thrown in - on line 8
~~~
**Example #8 Basic interface type declaration**
`<?php
interface I { public function f(); }
class C implements I { public function f() {} }
// This doesn't implement I.
class E {}
function f(I $i) {
echo get_class($i)."\n";
}
f(new C);
f(new E);
?>`
以上例程会输出:
~~~
C
Fatal error: Uncaught TypeError: Argument 1 passed to f() must implement interface I, instance of E given, called in - on line 13 and defined in -:8
Stack trace:
#0 -(13): f(Object(E))
#1 {main}
thrown in - on line 8
~~~
**Example #9 Nullable type declaration**
`<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>`
以上例程会输出:
~~~
object(C)#1 (0) {
}
NULL
~~~
#### 严格类型
默认情况下,如果能做到的话,PHP将会强迫错误类型的值转为函数期望的标量类型。 例如,一个函数的一个参数期望是[string](http://php.net/manual/zh/language.types.string.php),但传入的是[integer](http://php.net/manual/zh/language.types.integer.php),最终函数得到的将会是一个[string](http://php.net/manual/zh/language.types.string.php)类型的值。
可以基于每一个文件开启严格模式。在严格模式中,只有一个与类型声明完全相符的变量才会被接受,否则将会抛出一个**TypeError**。 唯一的一个例外是可以将[integer](http://php.net/manual/zh/language.types.integer.php)传给一个期望[float](http://php.net/manual/zh/language.types.float.php)的函数。
使用 [*declare*](http://php.net/manual/zh/control-structures.declare.php) 语句和*strict\_types* 声明来启用严格模式:
**Caution**
启用严格模式同时也会影响[返回值类型声明](http://php.net/manual/zh/functions.returning-values.php#functions.returning-values.type-declaration).
> **Note**:
>
> 严格类型适用于在*启用严格模式的文件内*的函数调用,而不是在那个文件内声明的函数。 一个没有启用严格模式的文件内调用了一个在启用严格模式的文件中定义的函数,那么将会遵循调用者的偏好(弱类型),而这个值将会被转换。
> **Note**:
>
> 严格类型仅用于标量类型声明,也正是因为如此,这需要PHP 7.0.0 或更新版本,因为标量类型声明也是在那个版本中添加的。
**Example #10 Strict typing**
```
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
```
以上例程会输出:
~~~
int(3)
Fatal error: Uncaught TypeError: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
thrown in - on line 4
~~~
**Example #11 Weak typing**
```
<?php
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
// These will be coerced to integers: note the output below!
var_dump(sum(1.5, 2.5));
?>
```
以上例程会输出:
~~~
int(3)
int(3)
~~~
**Example #12 Catching **TypeError****
```
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
try {
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
} catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}
?>
```
以上例程会输出:
~~~
int(3)
Error: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 10
~~~
### 可变数量的参数列表
PHP 在用户自定义函数中支持可变数量的参数列表。在 PHP 5.6 及以上的版本中,由 *...* 语法实现;在 PHP 5.5 及更早版本中,使用函数 [func\_num\_args()](http://php.net/manual/zh/function.func-num-args.php),[func\_get\_arg()](http://php.net/manual/zh/function.func-get-arg.php),和 [func\_get\_args()](http://php.net/manual/zh/function.func-get-args.php) 。
#### *...* in PHP 5.6+
In PHP 5.6 and later, argument lists may include the *...* token to denote that the function accepts a variable number of arguments. The arguments will be passed into the given variable as an array; for example:
**Example #13 Using *...* to access variable arguments**
```
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
```
以上例程会输出:
~~~
10
~~~
You can also use *...* when calling functions to unpack an [array](http://php.net/manual/zh/language.types.array.php) or **Traversable** variable or literal into the argument list:
**Example #14 Using *...* to provide arguments**
```
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
```
以上例程会输出:
~~~
3
3
~~~
You may specify normal positional arguments before the *...* token. In this case, only the trailing arguments that don't match a positional argument will be added to the array generated by *...*.
It is also possible to add a [type hint](http://php.net/manual/zh/language.oop5.typehinting.php) before the *...* token. If this is present, then all arguments captured by *...* must be objects of the hinted class.
**Example #15 Type hinted variable arguments**
```
<?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';
// This will fail, since null isn't a DateInterval object.
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
~~~
Finally, you may also pass variable arguments [by reference](http://php.net/manual/zh/functions.arguments.php#functions.arguments.by-reference) by prefixing the *...* with an ampersand (*&*).
#### Older versions of PHP
No special syntax is required to note that a function is variadic; however access to the function's arguments must use [func\_num\_args()](http://php.net/manual/zh/function.func-num-args.php), [func\_get\_arg()](http://php.net/manual/zh/function.func-get-arg.php) and [func\_get\_args()](http://php.net/manual/zh/function.func-get-args.php).
The first example above would be implemented as follows in PHP 5.5 and earlier:
**Example #16 Accessing variable arguments in PHP 5.5 and earlier**
```
<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
```
以上例程会输出:
~~~
10
~~~
- 序言
- 简介
- PHP是什么?
- PHP能做什么?
- 基本语法
- 类型
- boolean(布尔型)
- integer(整型)
- float(浮点型)
- string(字符串)
- array(数组)
- object(对象)
- callable(可调用)
- resource(资源)
- NULL(无类型)
- 伪类型
- 类型转换的判别
- 变量
- 基础
- 预定义变量
- 变量范围
- 可变变量
- 来自PHP之外的变量
- 常量
- 语法
- 魔术常量
- 表达式
- 运算符
- 运算符优先级
- 算术运算符
- 赋值运算符
- 位运算符
- 比较运算符
- 错误控制运算符
- 执行运算符
- 递增/递减运算符
- 逻辑运算符
- 字符串运算符
- 数组运算符
- 类型运算符
- 流程控制
- if
- else
- elseif/else if
- 流程控制的替代语法
- while
- do-whille
- for
- foreach
- break
- continue
- switch
- declare
- return
- require
- include
- require_once
- include_once
- goto
- 函数
- 用户自定义函数
- 函数的参数
- 返回值
- 可变函数
- 内部 (内置)函数
- 匿名函数
- 类与对象
- 简介
- 基本概念
- 属性
- 类的自动加载
- 构造函数
- 访问控制(可见性)