# 函数的参数

类型声明允许函数在调用时要求参数为特定类型。 如果给出的值类型不对，那么将会产生一个错误。为了指定一个类型声明，类型应该加到参数名前。这个声明可以通过将参数的默认值设为 `NULL` 来实现允许传递 `NULL` 。

| 类型        | 描述                               |
| ----------- | ---------------------------------- |
| 类/接口名称 | 参数必须是给定的类或实现接口的实例 |
| self        | 参数必须是与定义方法的类相同的实例 |
| array       | 参数必须是数组                     |
| callable    | 参数必须是可调用类型               |
| bool        | 参数必须是布尔类型                 |
| float       | 参数必须是浮点型                   |
| int         | 参数必须是整型                     |
| string      | 参数必须是字符串                   |

默认情况下，函数参数通过值传递（因而即使在函数内部改变参数的值，它并不会改变函数外部的值）。

```php
<?php

/**
 * Pass an array to the function.
 *
 * @param  array  $foo
 * @return void
 */
function foo(array $foo)
{
    unset($foo[1]);
}

$foo = [2, 4, 5];
foo($foo);
var_dump($foo); // array(3) { [0]=> int(2) [1]=> int(4) [2]=> int(5) }

```

如果希望允许函数修改它的参数值，必须通过引用传递参数。

```php
<?php

/**
 * Passing function parameters by reference.
 *
 * @param  array  &$foo
 * @return void
 */
function foo(array &$foo)
{
    unset($foo[1]);
}

$foo = [2, 4, 5];
foo($foo);
var_dump($foo); // array(2) { [0]=> int(2) [2]=> int(5) }

```

PHP 还允许使用数组和特殊类型 `NULL` 作为默认参数。默认值必须是常量表达式，不能是诸如变量，类成员，或者函数调用等。注意当使用默认参数时，任何默认参数必须放在任何非默认参数的右侧。否则，函数将不会按照预期的情况工作。

```php
<?php

/**
 * Use default parameters in function.
 *
 * @param  array       $foo
 * @param  string|null $bar
 * @return void
 */
function foo(array $foo = [], ?string $bar = null)
{
    //
}

$foo = [2, 4, 5];
$bar = 'bar';
foo();
foo($foo);
foo($foo, null);
foo($foo, $bar);

```

基本类参数类型声明。

```php
<?php

/**
 * Basic class parameter type declaration.
 *
 * @param  Foo    $instance
 * @return string
 */
function foo(Foo $instance): string
{
    return get_class($instance);
}

class Foo
{
    //
}

class Bar extends Foo
{
    //
}

class Baz
{
    //
}

var_dump(foo(new Foo())); // string(3) "Foo"
var_dump(foo(new Bar())); // string(3) "Bar"
var_dump(foo(new Baz())); // PHP Fatal error:  Uncaught TypeError: Argument 1 passed to foo() must be an instance of Foo, instance of Baz given.

```

基本接口参数类型声明。

```php
<?php

/**
 * Basic interface parameter type declaration.
 *
 * @param  Foo    $instance
 * @return string
 */
function foo(Foo $instance): string
{
    return get_class($instance);
}

interface Foo
{
    //
}

class Bar implements Foo
{
    //
}

class Baz
{
    //
}

var_dump(foo(new Bar())); // string(3) "Bar"
var_dump(foo(new Baz())); // PHP Fatal error:  Uncaught TypeError: Argument 1 passed to foo() must implement interface Foo, instance of Baz given.

```

默认情况下，如果能做到的话， PHP 将会强迫错误类型的值转为函数期望的标量类型。 例如，一个函数的一个参数期望是字符串，但传入的是整型，最终函数得到的将会是一个字符串类型的值。可以基于每一个文件开启严格模式。在严格模式中，只有一个与类型声明完全相符的变量才会被接受，否则将会抛出一个 `TypeError` 。 唯一的一个例外是可以将整型传给一个期望浮点数的函数。使用 `declare` 语句和 `strict_types` 声明来启用严格模式。启用严格模式同时也会影响返回值类型声明。严格类型适用于在启用严格模式的文件内的函数调用，而不是在那个文件内声明的函数。

```php
<?php

declare(strict_types=1);

/**
 * Calculate the sum of two integers.
 *
 * @param  int    $a
 * @param  int    $b
 * @return int
 */
function foo(int $a, int $b): int
{
    return $a + $b;
}

var_dump(foo(1, 2));     // int(3)
var_dump(foo(1.5, 2.5)); // PHP Fatal error:  Uncaught TypeError: Argument 1 passed to foo() must be of the type int, float given.

```

一个没有启用严格模式的文件内调用了一个在启用严格模式的文件中定义的函数，那么将会遵循调用者的偏好（弱类型），而这个值将会被转换。

```php
<?php

/**
 * Calculate the sum of two integers.
 *
 * @param  int    $a
 * @param  int    $b
 * @return int
 */
function foo(int $a, int $b): int
{
    return $a + $b;
}

var_dump(foo(1, 2));     // int(3)
var_dump(foo(1.5, 2.5)); // int(3)

```

PHP 在用户自定义函数中支持可变数量的参数列表。参数列表可能包含 `...` 标记，表示该函数接受可变数量的参数。参数将作为数组传递给给定变量。

```php
<?php

/**
 * Calculate the sum of all integers.
 *
 * @param  int $number
 * @return int
 */
function foo(int ...$number): int
{
    $sum = 0;
    foreach ($number as $value) {
        $sum += $value;
    }
    return $sum;
}

var_dump(foo(1, 2, 3, 4)); // int(10)

```

还可以使用 `...` 在调用函数时将数组或 `Traversable` 变量或文字解压缩到参数列表中。

```php
<?php

/**
 * Calculate the sum of two integers.
 *
 * @param  int    $a
 * @param  int    $b
 * @return int
 */
function foo(int $a, int $b): int
{
    return $a + $b;
}

var_dump(foo(...[1, 2])); // int(3)

```

