Menu

PHPの無名関数とクロージャ:useキーワードの使い方

無名関数(クロージャ)は、変数に入れた名前のない関数です:$greet = function ($name) { return "Hi $name"; };。useキーワード、参照によるキャプチャ、callable、ファーストクラスcallable構文strlen(...)、クラスの中のクロージャを学びます。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

無名関数はクロージャとも呼ばれ、名前のない関数です。値が期待される場所にfunction ($param) { ... }と書き、変数に代入したり、ほかの関数に渡したり、返したりします。use ($var)で周りのコードの変数を持ち込めます。

すべての無名関数は組み込みクラスClosureのオブジェクトなので、保存したり、受け渡したり、あとで$greet(...)で呼び出したりできます。

useキーワードは値でキャプチャする

クロージャは自分では外側の変数を参照できません。use ($x)は、クロージャが実行されるときではなく、作られた瞬間の$xの値をクロージャにコピーします。

参照によるuse:&$var

use (&$x)はコピーではなく変数そのものをクロージャに渡します。クロージャの中での変更は外から見え、外での変更も中から見えます。コールバックで合計に足したり、カウンターを保持したりするのはこの方法です。

makeCounter()を呼ぶたびに新しい$countが作られ、返されたクロージャは関数が戻ったあともそれを保持し続けます。「クロージャ」という言葉が指しているのはこれで、関数が必要な変数を閉じ込めるのです。

コールバックとしてクロージャを渡す

array_map()、array_filter()、usort()、array_walk()のような関数は、関数を引数として受け取ります。クロージャを使えば、必要なだけ文を書いてその場で関数を書けます。

本体が1つの式なら、fn($p) => $p['price']のようなアロー関数のほうが短く、useも要りません。

callable:関数名、メソッド、strlen(...)

callable型の引数はクロージャ以外も受け付けます。関数名の文字列、オブジェクトとメソッド名の配列、クラス名と静的メソッド名の配列も該当します。PHP 8.1以降は、ファーストクラスcallable構文strlen(...)で、そのどれでも直接Closureにできます。

(...)の形はその行が実行された時点でチェックされ、タイプミスがあればその場でErrorが投げられます。'strtoupr'のような文字列は、誰かが呼び出そうとするまでただの文字列です。

クラスの中のクロージャ:$thisとstatic

メソッドの中で作られたクロージャには自動的に$thisが結びつけられるので、オブジェクトのプロパティを使えます。$thisが不要ならstatic functionにしましょう。オブジェクトを生かし続けるのも防げます。

useの書き忘れ

クロージャでいちばんよくあるバグは、外側の変数をuseに並べずに使うことです。クロージャの中ではその変数は存在しません。

$minAge = 18;
$adults = array_filter($people, function ($p) {
    return $p['age'] >= $minAge;   // $minAge is not in use (...)
});
PHP prints: Warning: Undefined variable $minAge

中では$minAgeはnullで、どんな年齢も>= nullの比較でtrueになるので、全員が絞り込みを通ってしまいます。警告を表示しないサーバーでは、何も教えてくれません。変数をuseに加えましょう。

よくある質問

PHPのクロージャとは何ですか?

function (...) { ... }で作り、変数に入れたり引数として渡したりする名前のない関数です。PHPはこれをClosureクラスのオブジェクトとして表します。作られたスコープの変数を、use (...)に並べて持ち込めます。

PHPのクロージャのuseキーワードは何をしますか?

use ($x)は、クロージャが作られるときに外側の変数$xをクロージャにコピーします。そのあと外で$xを変えても見えません。代わりに変数を共有するにはuse (&$x)と書き、変更が双方向に伝わるようにします。

PHPのcallableとは何ですか?

PHPが呼び出せるものすべてです。クロージャ、文字列の関数名('strtoupper')、配列[$object, 'method']や[ClassName::class, 'staticMethod']、__invoke()を持つオブジェクトです。どれでも受け付けるにはcallable型を、確認するにはis_callable()を使います。

PHPのstrlen(...)はどういう意味ですか?

PHP 8.1のファーストクラスcallable構文です。strlen(...)は関数を呼ばずに、そこからClosureを作ります。メソッド($obj->method(...))や静的メソッド(Foo::bar(...))にも使え、文字列の名前と違って、その行が実行された時点でチェックされます。

無名関数のあとにセミコロンは必要ですか?

代入するときは必要です。$f = function () { ... };は代入文なので、;で終わります。省くと構文エラーになります。引数として直接渡すクロージャには、それ自体のセミコロンは不要です。

Coddyのプログラミング言語のイラスト

Coddyでコードを学ぼう

始める