2018/12/30 php,無名関数、クロージャー、など パート2

次にクロージャについて。

クロージャとは、関数Aの宣言内で、関数Aの返り値として無名関数Bを返す。

そして外側関数Aを実行した返り値(無名関数)を変数に代入する。つまりラムダ関数。

クロージャは、変数の値として使用することもできます。 PHP は、そのような記述があると自動的に内部クラスClosure のインスタンスに変換します。

http://php.net/manual/ja/functions.anonymous.php

具体例として

https://qiita.com/tricogimmick/items/3e344486658e3cfbd407


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

こんな感じ。内側の赤文字部分がクロージャ。

グローバルシンボルテーブル「$counter」が無名関数を指していて、無名関数内の関数シンボルテーブル$countが、無名関数外(create_counter関数内)の$countを指しているので、create_counter関数実行終了後も$countの値は消えない、ということか?




<?php
// 基本的なショッピングカートで、追加した商品の一覧や各商品の
// 数量を表示します。カート内の商品の合計金額を計算するメソッド
// では、クロージャをコールバックとして使用します。
class Cart
{
const PRICE_BUTTER  = 1.00;
const PRICE_MILK    = 3.00;
const PRICE_EGGS    = 6.95;

protected $products = array();

public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}

public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}

public function getTotal($tax)
{
$total = 0.00;

        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                $pricePerItem = constant(__CLASS__ . “::PRICE_” .
                    strtoupper($product));
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };

array_walk($this->products, $callback);
return round($total, 2);
}
}

$my_cart = new Cart;

// カートに商品を追加します
$my_cart->add(‘butter’, 1);
$my_cart->add(‘milk’, 3);
$my_cart->add(‘eggs’, 6);

// 合計に消費税 5% を付加した金額を表示します
print $my_cart->getTotal(0.05) . “\n”;
// 結果は 54.29 です
?>


クロージャの定義をこのページの最初に記述したものだとすると↑のカートの例の無名関数はクロージャではないような気がするが、ラムダ関数(無名関数を変数に代入して、

変数名();

として無名関数を実行する)ではある。

https://qiita.com/tricogimmick/items/3e344486658e3cfbd407

のカウンタの例との共通点は、ラムダ関数を実行して、無名関数の外の変数が状態を保持することで計算結果(カウント回数や金額合計)が求められる、ということ。

カートの例はarray_walk関数があるのでわかりにくいが、結局array_walk実行中にラムダ関数$callbackが、$productsの要素数分繰り返されている。

コメントを残す

メールアドレスが公開されることはありません。