連載
» 2017年10月11日 05時00分 公開

Web業界で働くためのPHP入門(11):PHPの少し変わった関数の使い方――引数のデフォルト値、可変長引数、可変関数、コールバック関数、クロージャ (1/2)

オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。今回は、少し変わった関数の使い方について解説します。具体的には、引数のデフォルト値、可変長引数、コールバック関数、クロージャなどを扱います。

[齊藤新三(改訂)/山田祥寛(改訂監修),WINGSプロジェクト]

 オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載「Web業界で働くためのPHP入門」。今回は、少し変わった関数の使い方について解説します。具体的には、引数のデフォルト値、可変長引数、コールバック関数、クロージャなどを扱います。

引数の省略とデフォルト値

 連載第9回『PHPの「関数」で処理を共通化して再利用する』で紹介した関数の引数ですが、省略することが可能です。ただ、そのためには関数定義の際にデフォルト値を設定する必要があります。

引数は、そのままでは省略できない

 例で見ていきましょう。以下のuseDefaultArgs.phpを作成し、実行してください。

<?php
function concatenate(string $firstName, string $lastName, string $space): string
{
    return $lastName.$space.$firstName;
}
 
$lName = "齊藤";
$fName = "新三";
$name1 = concatenate($fName, $lName, " ");
print("半角スペースで結合: ".$name1);
$name2 = concatenate($fName, $lName, "");
print("<br>スペースなしで結合: ".$name2);
リスト1 phplesson/chap11/useDefaultArgs.php

 実行結果は以下の通りです。

半角スペースで結合: 齊藤 新三
スペースなしで結合: 齊藤新三

 ここで作成した関数に関しては特に難しいものではありません。第1引数として氏名の名を、第2引数として氏名の姓を受け取り、それらを第3引数でつないだ文字列を戻り値とするというものです。実行部分では、1つ目のサンプルとして半角スペースでつないでいます。2つ目はスペースなしでつなぎたいので第3引数に空文字「""」を指定しています。

 ここで少し考えてみます。半角スペースや「・」など特定の文字の場合は確かに第3引数で指定する必要があります。一方、空文字の場合はそもそも引数が不要なのではないでしょうか。つまり、11行目は以下のようにしてはダメなのでしょうか。

 試しに、11行目をこのように書き換えて実行してみてください。

$name2 = concatenate($fName, $lName);

 以下のようにエラーになります。

Fatal error: Uncaught ArgumentCountError: Too few arguments to function concatenate(), 2 passed in C:\xampp\htdocs\phplesson\chap11\useDefaultArgs.php on line 11 and exactly 3 expected in C:\xampp\htdocs\phplesson\chap11\useDefaultArgs.php:2 Stack trace: #0 C:\xampp\htdocs\phplesson\chap11\useDefaultArgs.php(11): concatenate('\xE6\x96\xB0\xE4\xB8\x89', '\xE9\xBD\x8A\xE8\x97\xA4') #1 {main} thrown in C:\xampp\htdocs\phplesson\chap11\useDefaultArgs.php on line 2

 エラー内容としては、「関数の引数が不足している」というものです。確かにその通りです。このように、関数の引数として定義されているものは、たとえ不要に感じても全て渡してあげる必要があります。

引数の省略を可能にするデフォルト値

 一方で、やはり空文字の場合は、わざわざ引数を書くのは無駄に思えます。そこで、第3引数を省略可能とし、第3引数が渡されない場合は空文字を適用するようにする方法があります。それが「引数のデフォルト値」です。リスト1のuseDefaultArgs.phpの第3引数を省略可能にした以下のuseDefaultArgs2.phpを作成し、実行してください。

<?php
function concatenate(string $firstName, string $lastName, string $space = ""): string
{
    return $lastName.$space.$firstName;
}
 
$lName = "齊藤";
$fName = "新三";
$name1 = concatenate($fName, $lName, " ");
print("半角スペースで結合: ".$name1);
$name2 = concatenate($fName, $lName);
print("<br>スペースなしで結合: ".$name2);
リスト2 phplesson/chap11/useDefaultArgs2.php

 実行結果はリスト1と同じです。

 変わったところは関数の第3引数が以下の記述になったところです。

$space = ""

 このように引数の定義部分で「引数 = 値」と記述することで、その引数が省略された場合のデフォルト値を指定できます。デフォルト値を設定したので、空文字で結合する場合は引数を記述する必要がなくなります。そのため、11行目では第3引数が省略されています。

 これが引数のデフォルト値と省略です。

 なお、第9回の『「関数リファレンス」を見よう』の際に、引数が[ ]で囲まれていることを紹介しましたが、これこそがまさに引数のデフォルト値と省略です。

可変長引数

 リスト1やリスト2では引数として姓と名の2個を渡しています。人によっては、名前が2個とは限らない人もいます。ミドルネームも含めれば3個、4個と増え、ピカソのように長い人もいます。国によっては数が定まりません。そういったのに対応するにはどうしたらいいのでしょうか。

 PHPでは、引数の個数を限定しない「可変長引数」()というのがあります。それを使います。

可変長引数は、PHP 5.6で導入されたものです。従って、5.5以前の動作環境では以下のソースコードは動きません。

可変長引数はドット3個

 例を見てみましょう。以下のuseVariableLengthArgs.phpを作成し、実行してください。

<?php
function concatenate(string ...$name): string
{
    $concatenatedName = "";
    for($i = 0; $i < count($name); $i++) {
        $concatenatedName .= $name[$i];
        if($i != count($name) - 1) {
            $concatenatedName .= "・";
        }
    }
    return $concatenatedName;
}
 
$lName = "齊藤";
$fName = "新三";
$name1 = concatenate($fName, $lName);
print("結合結果: ".$name1);
$picasso = concatenate("パブロ", "ディエゴ", "ホセ", "フランシスコ", "デ", "パウラ", "ファン", "ネポムセーノ", "マリア", "デ", "ロス", "レメディオス", "シプリアノ", "デ", "ラ", "サンティシマ", "トリニダード", "ルイス", "ピカソ");
print("<br>ピカソの本名: ".$picasso);
リスト3 phplesson/chap11/useDefaultArgs.php

 実行結果は以下の通りです。

結合結果: 新三・齊藤
ピカソの本名: パブロ・ディエゴ・ホセ・フランシスコ・デ・パウラ・ファン・ネポムセーノ・マリア・デ・ロス・レメディオス・シプリアノ・デ・ラ・サンティシマ・トリニダード・ルイス・ピカソ

 ここでのポイントは2行目の関数の引数として記述された以下のコードです。

...$name

 この引数の前に記述されたドット3個「...」が可変長引数を表します。可変長引数の関数を利用する場合は、リスト3の16行目や18行目を見ても分かるように、引数を幾つでも渡すことができます。

 また、関数内部では、リスト3の6行目の記述を見ても分かるように、この引数は配列として扱います。

 リスト3の5〜10行目では、この配列をループ処理しながらそれぞれの名前の要素を文字列結合しています。結合の間には「・」を使っています。ただ、そのままループ処理をしたならば結合が完成した名前の最後にも「・」が付いてしまいます。そこを判定し、最後のループ以外は「・」を付ける処理にしているのが7行目のifです。

ドット3個は関数外でも使える

 ここで、ドット3個の違う使い方を紹介します。それは関数外で使う方法です。例を見てみましょう。以下のuse3DotsToken.phpを作成し、実行してください。

<?php
function concatenate(string $firstName, string $lastName, string $space = ""): string
{
    return $lastName.$space.$firstName;
}
 
$nameParam1 = ["新三", "齊藤", "・"];
$name1 = concatenate(...$nameParam1);
print("・で結合: ".$name1);
$nameParam2 = ["新三", "齊藤"];
$name2 = concatenate(...$nameParam2);
print("<br>空文字で結合: ".$name2);
リスト4 phplesson/chap11/use3DotsToken.php

 実行結果は以下の通りです。

・で結合: 齊藤・新三
空文字で結合: 齊藤新三

 関数部分はリスト2と同じです。ここでは実行部分が違います。注目するのは、8行目の引数を渡している以下の部分です。

concatenate(...$nameParam1)

 本来、引数はリスト2のようにカンマ区切りでそれぞれ列挙する必要があります。

concatenate($fName, $lName, " ")

 ところがリスト4では、それらを7行目で配列変数$nameParam1として用意し、それを引数として渡しています。そのときに、以下のようにそのまま渡すだけでは単に第1引数として扱われてしまい、もちろん引数不足でエラーとなります。

concatenate($nameParam1)

 配列の各要素を各引数に展開してくれるのがドット3個の働きです。

図1 リスト4の引数の展開

 図1の動きが理解できると、配列の要素数が2個の$nameParam2を引数で渡した11行目の動きも理解できます。第3引数としてはデフォルト値が使われているのが分かります。

       1|2 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。