PHP 無名関数
無名関数 ¶
無名関数はクロージャとも呼ばれ、 関数名を指定せずに関数を作成できるようにするものです。 callable パラメータとして使う際に便利ですが、用途はそれにとどまりません。
無名関数の実装には Closure クラスを使っています。
変数の値として使用できる
クロージャは、変数の値として使用することもできます。 PHP は、そのような記述があると自動的に内部クラス Closure のインスタンスに変換します。 変数へのクロージャの代入は、他の代入と同じように記述し、 同じく最後にセミコロンをつけます。
例2 変数への無名関数の代入
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
useを用いて親のスコープから変数を引き継ぐ
クロージャは、変数を親のスコープから引き継ぐことができます。 引き継ぐ変数は、use で渡さなければなりません。 PHP 7.1 以降は、引き継ぐ値に スーパーグローバル や $this、 およびパラメータと同じ名前の変数を含めてはいけません。
戻り値の型は、 use の 後 に置かなければいけません。
例3 親のスコープからの変数の引き継ぎ
<?php
$message = 'hello';
// "use" がない場合
$example = function () {
var_dump($message);
};
$example();
// $message を引き継ぎます
$example = function () use ($message) {
var_dump($message);
};
$example();
// 引き継がれた変数の値は、関数が定義された時点のものであり、
// 関数が呼ばれた時点のものではありません
$message = 'world';
$example();
// $message をリセットします
$message = 'hello';
// リファレンス渡しで引き継ぎます
$example = function () use (&$message) {
var_dump($message);
};
$example();
// 親のスコープで変更された値が、
// 関数呼び出しの内部にも反映されます
$message = 'world';
$example();
// クロージャは、通常の引数も受け付けます
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
// 戻り値の型は、use の後に置きます
$example = function () use ($message): string {
return "hello $message";
};
var_dump($example());
?>
上の例の出力は、 たとえば以下のようになります。
Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"
string(11) "hello world"
参照渡しと値渡しの違い
##「値渡し」とは、変数に代入した値の"コピー"を渡します。
// 変数bに代入した後に変数aの値を変えても
// 変数bは変わりありません。
$a = 2;
$b = $a; // 変数aを代入
$a = 10; // 変数aの値を変更
echo $b;
# 結果
2
「参照渡し」とは、変数に代入した値の”参照先”(= 値の入れ物) を渡します。
// 変数bに代入した後に変数aの値を
// 変えたところ、変数bの値も変わります。
$a = 2;
$b =& $a; // 変数aを&をつけて代入
$a = 10; // 変数aの値を変更
echo $b;
# 結果
10
Laravel クエリビルダでのクロージャ
判定式によって検索条件を変更する
「リクエストであのパラメータが来た場合は、検索条件にこれを追加する」
のような流れは良くあるパターンです。
Laravelのクエリビルダには、そのパターンでのSQL文組み立てにも対応しています。
when()メソッドを使い、第一引数に判定式の結果(trueもしくはfale)、第二引数にクロージャを指定し、trueであった場合の処理をクロージャに定義します。
$user_id = 8;
$data = $users
->when($user_id, function ($query) use ($user_id) {
return $query->where('id', $user_id);
})
->get();
上記例の場合、
「$user_idがtrue(すなわち、値が入っている)の場合は、idカラムをその値で指定する」
という条件が追加されます。