読者です 読者をやめる 読者になる 読者になる

パーフェクトPHPのクロージャの説明が全然わからなかった

PHP

というありがたい環境の中で現在もっぱらパーフェクトPHPの書籍にて勉強させていただいてます。そのパーフェクトPHPの中でクロージャの説明がよくわからなかったです。

クロージャとは、関数内に現れる変数の名前解決が、ローカルスコープだけでなく関数が定義された場所のスコープも含めて行われる関数のことです。

???

よくわからなかったので調べてみても、「無名関数はクロージャとも呼ばれる」みたいなことが書いてあって、なんかちょっと違うような気がしました。そんな中で下のエントリがとてもわかりやすかったです。

sekai.hatenablog.jp

要するに無名関数の中では無名関数の外の変数は見えないのでuse()で見えるようにしましょうということでしょうか。

<?php
function method() {
    $hello = 'hello';
    $closure = function() {
        echo "${hello}! world!", PHP_EOL;  // Notice:  Undefined variable: hello…
    };
    $closure();
}
method();

としても5行目の無名関数の中で$helloが見えないので実行時エラーNotice: Undefined variable: hello…になります。  
 
 
そのため下のように引数で渡すようにもできます。

<?php
function method() {
    $hello = 'hello';
    $closure = function($greeting) {
        echo "${greeting}! world!", PHP_EOL;
    };
    $closure($hello);  // => hello! world!
}
method();

 
 
ただこれだと無名関数に渡したいものが増えた時に引数を増やしたりでメソッドの仕様が変わってしまうので、その時にuse()を使えば便利ですよってことです。

<?php
function method() {
    $hello = 'hello';
    $closure = function() use ($hello){
        echo "${hello}! world!",  PHP_EOL;
    };
    $closure();  // => hello! world!
}
method();

 
 
この場合のuse()で渡す$helloは値渡しなので無名関数内で書き換えても外側の$helloは書き換えられません。

<?php
function method() {
    $hello = 'hello';
    $closure = function() use ($hello){
        $hello = 'goodby';
        echo "${hello}! world!",  PHP_EOL;
    };
    $closure();  // => goodby! world!
    echo $hello; // => hello
}
method();

 
 
無名関数の中で書き換えたい場合はuse()で参照渡しができます。

<?php
function method() {
    $hello = 'hello';
    $closure = function() use (&$hello){  //参照渡し
        $hello = 'goodby';
        echo "${hello}! world!",  PHP_EOL;
    };
    $closure();  // => goodby! world!
    echo $hello; // => goodby
}
method();

 
 
ということでOKかな!

ちなみにですがクロージャの概念を知るにはこれがわかりやすかったです!まさにuse()でローカルスコープ外の変数を捉えるということですね。

qiita.com

その上でパーフェクトPHPで書いてる内容をみたら言ってることの意味がわかった。。要するにクロージャの概念が全くわかってなかったということでした。ちゃんちゃん。