## 函數的參數
通過參數列表可以傳遞信息到函數,即以逗號作為分隔符的表達式列表。參數是從左向右求值的。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
- 函數
- 用戶自定義函數
- 函數的參數
- 返回值
- 可變函數
- 內部 (內置)函數
- 匿名函數
- 類與對象
- 簡介
- 基本概念
- 屬性
- 類的自動加載
- 構造函數
- 訪問控制(可見性)