PHP再勉強中です。
PHP5.3で導入された無名関数はクロージャーとして使用することができるとのこと。
ただしPHPの場合、親のスコープから引き継ぐ変数はuse
を利用して明示的に引き渡す必要があります。
クロージャーのサンプル
クロージャーを用いた単純なカウンターのコードは以下のようになります。
<?php
function create_counter()
{
$count = 0;
return function() use (&$count) {
return ++$count;
};
}
$counter = create_counter();
echo $counter() . PHP_EOL; # => 1
echo $counter() . PHP_EOL; # => 2
echo $counter() . PHP_EOL; # => 3
create_counter()
関数内で宣言されたローカル変数$count
は、本来create_counter()
関数を抜けた時点で消滅する筈ですが、create_counter()
関数の戻り値として生成された無名関数にuse
で引き渡されているために、create_counter()
関数を抜けた後も存続することになります。
この時、無名関数内でカウンターとして$count
をインクリメントするため、use
には参照として渡す必要があります。(ここらへんちょっとめんどくさい)
このサンプルのような単純なケースの場合、静的変数を利用しても同様な処理は記述できますが、クロージャーを利用することでカウンターを保持する変数を関数内に閉じ込めることででき、また以下のように複数のカウンターを生成することも容易です。
$counter1 = create_counter();
$counter2 = create_counter();
echo $counter1() . PHP_EOL; # => 1
echo $counter2() . PHP_EOL; # => 1
echo $counter1() . PHP_EOL; # => 2
echo $counter2() . PHP_EOL; # => 2
クロージャーを返すメソッド
関数だけでなく、オブジェクトのメソッドもクロージャーを返すことができます。
<?php
class MyClass
{
private $foo = "Foo";
public function getFoo()
{
return function() { return $this->foo; };
}
}
$obj = new MyClass();
$foo = $obj->getFoo();
echo $foo() . PHP_EOL; # => "Foo"
PHP5.4以上であれば、メソッド内で生成された無名関数には暗黙的に$this
が引き渡されているので、無名関数内で使用することが可能です。
PHP5.3の場合、$this
を一度ほかの変数に代入後、その変数を無名関数にuse
で明示的に引き渡す必要があります(筈)。
<?php
class MyClass
{
private $foo = "Foo";
public function getFoo()
{
# $this を変数に代入して無名関数に引き渡す。
$self = $this;
return function() use (&$self) { return $self->foo; };
}
}