LoginSignup
128
129

More than 5 years have passed since last update.

PHPでクロージャーを使う

Posted at

PHP再勉強中です。

PHP5.3で導入された無名関数はクロージャーとして使用することができるとのこと。

参考:Wikipedia : クロージャー

ただし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; };
    }
}
128
129
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
128
129