関数の引数

引数のリストにより関数へ情報を渡すことができます。 このリストは、カンマで区切られた式のリストです。 引数の評価は、関数が実際にコールされる前に、 左から右の順番で行われます(先行評価)。

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 .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // 出力は 'This is a string, and something extra.' となります
?>

リファレンス渡しが想定されているところに、値渡しを行うとエラーになります。

デフォルト引数値

関数は、変数に代入する記法に似たやり方で、 デフォルト値を引数に定義することができます。 デフォルト値は引数が指定されなかった場合に使われますが、 null を渡した場合はデフォルト値を代入 しない ことに特に注意して下さい。

例4 関数におけるデフォルト引数の使用法

<?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.

デフォルト引数の値には、スカラー値、 配列、および特殊な型 null を指定できます。 PHP 8.1.0 以降では、 new ClassName() 記法を使ってオブジェクトも指定できます。

例5 スカラー型以外をデフォルト値として使用する

<?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");?>

例6 オブジェクトをデフォルト値として使用する(PHP 8.1.0 以降)

<?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);
?>

デフォルト値は、定数式である必要があり、 (例えば) 変数やクラスのメンバーであってはなりません。

デフォルト値を有する引数は、 デフォルト値がない引数の右側に全てある必要があることに注意して下さい。 そうでない場合、デフォルト値を指定していても、 呼び出し時に省略できません。 次の簡単なコードを見てみましょう。

例7 関数の引数のデフォルト値の 間違った使用法

<?php
function makeyogurt($container = "bowl", $flavour)
{
    return "Making a $container of $flavour yogurt.\n";
}
 
echo makeyogurt("raspberry"); // $container に "raspberry" を指定します。$flavour ではありません。
?>

上の例の出力は以下となります。

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

ここで、上の例を次のコードと比べてみましょう。

例8 関数の引数のデフォルト値の 正しい使用法

<?php
function makeyogurt($flavour, $container = "bowl")
{
    return "Making a $container of $flavour yogurt.\n";
}
 
echo makeyogurt("raspberry"); // $flavour に "raspberry" を指定します。
?>

上の例の出力は以下となります。

Making a bowl of raspberry yogurt.

PHP 8.0.0 以降では、 デフォルト値を指定した引数を複数スキップするために、 名前付き引数 が使えます。

例9 関数の引数のデフォルト値の 正しい使用法

<?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.

PHP 8.0.0 以降では、 デフォルト値を指定した引数の後に、 必須の引数を宣言することは 推奨されません。 なぜなら、そのデフォルト値は絶対に使われないからです。 これは、デフォルト値を削除することで解決できます。 このルールの唯一の例外は、 Type $param = null と書かれた引数です。 null をデフォルトにすることは、 型が暗黙のうちに nullable であることを示しています。 この書き方はまだ許可されていますが、 以下のようにして 明示的に nullable 型 を使うことを推奨します:

例10 デフォルト値を指定した引数は、必須の引数の後に宣言する

<?php
 function foo($a = [], $b) {} // デフォルト値が使われないため、PHP 8.0.0 以降は推奨されません
 function foo($a, $b) {}      // 上のコードと機能的には同じですが、推奨されない警告は発生しません。

 function bar(A $a = null, $b) {} // まだ許可されています。$a は必須ですが、nullable です。
 function bar(?A $a, $b) {}       // 推奨される書き方です。
 ?>

注意: PHP 7.1.0 以降では、 デフォルト値を指定しないで引数を省略すると、 ArgumentCountError がスローされるようになりました。 これより前のバージョンでは、警告が発生していました。

注意: リファレンス渡しの引数にもデフォルト値を指定できます。

可変長引数リスト

PHP は ... を使った可変長引数をユーザー定義関数でサポートしています。

引数リストに ... トークンを含めることで、 その関数が可変長の引数を受け取ることを示せます。 引数は、指定した変数に配列として渡されます:

例11 ... を使った、可変長引数へのアクセス

<?php
function sum(...$numbers) {
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}

echo sum(1, 2, 3, 4);
?>

上の例の出力は以下となります。

10

関数を呼び出すときに ... を使うと、 配列や Traversable を実装した変数やリテラルを引数リストに展開することができます。

例12 引数での ... の使用例

<?php
function add($a, $b) {
    return $a + $b;
}

echo add(...[1, 2])."\n";

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

上の例の出力は以下となります。

3
3

通常の引数を、... の前に指定することもできます。 この場合は、通常の引数リストにマッチしなかったのこりの引数が ... による配列に追加されます。

... トークンの前に、 型宣言 を付加することもできます。 型宣言がある場合、... が取り込むすべての引数はその型に一致していなければいけません。

例13 型宣言つきの可変長引数

<?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);
?>

上の例の出力は以下となります。

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 から名前付き引数が導入されました。 名前付き引数は、位置ではなく、名前ベースで引数を渡すことを可能にします。 これによって、引数の意味が自己文書化(self-documenting)され、 引数を任意の順番で渡せるようになり、任意のデフォルト値を持つ引数をスキップできるようになります。

名前付き引数は、引数の名前の後にコロンを付けたものを、値の前に付けることで指定します。 引数の名前に予約語を使うことも許されています。 引数の名前は識別子でなければならず、動的に指定することは出来ません。

例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 同じ引数を複数回渡すと、Error がスローされる

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

foo(param: 1, param: 2);
// Error: Named parameter $param overwrites previous argument
foo(1, param: 2);
// Error: Named parameter $param overwrites previous argument
?>

PHP 8.1.0 以降では、 引数を ... で展開した後に 名前付き引数を指定することができます。 名前付き引数は、展開済みの引数を上書きしては いけません

例19 引数を展開した後に、名前付き引数を使う

<?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. Named parameter $b overwrites previous argument
?>