PHP学習 - PHPクロージャ
PHPクロージャ(Closure)は、PHP5.3で導入された匿名関数です。
クロージャの構文は非常に単純で、注意が必要なキーワードはクロージャと外部変数を接続することです。
<span style="color: #800080;">$a</span> = <span style="color: #0000ff;">function</span>() <span style="color: #0000ff;">use</span>(<span style="color: #800080;">$b</span>) {}
簡単な例は次のとおりです:
<span style="color: #0000ff;">function</span> <span style="color: #0000ff;">callback</span>(<span style="color: #800080;">$fun</span><span style="color: #000000;">) {</span><span style="color: #800080;">$fun</span><span style="color: #000000;">();}</span><span style="color: #800080;">$msg</span> = "Hello, everyone"<span style="color: #000000;">;</span><span style="color: #800080;">$fun</span> = <span style="color: #0000ff;">function</span> () <span style="color: #0000ff;">use</span>(<span style="color: #800080;">$msg</span><span style="color: #000000;">) {</span><span style="color: #0000ff;">print</span> "This is a closure use string value, msg is: <span style="color: #800080;">$msg</span>. <br />/n"<span style="color: #000000;">;};</span><span style="color: #800080;">$msg</span> = "Hello, everybody"<span style="color: #000000;">;</span><span style="color: #0000ff;">callback</span>(<span style="color: #800080;">$fun</span>);
結果は次のようになります: これはクロージャを使用する文字列ですvalue、msg は次のとおりです。皆さん、こんにちは。
/n
PHP の新しく開かれたクロージャ構文では、クロージャの外側で定義された変数を使用するために use を使用します。 ここでは外部変数 $msg を使用します。定義後、その値はクロージャーの実行後に変更され、元の値が出力されます。 基本型 パラメータは値によって渡され、クロージャの使用値はクロージャの作成時に決定されます。
小さなアプリケーションは次のとおりです:
<span style="color: #008000;">/*</span><span style="color: #008000;">* * 一个利用闭包的计数器产生器 * 这里其实借鉴的是python中介绍闭包时的例子... * 我们可以这样考虑: * 1. counter函数每次调用, 创建一个局部变量$counter, 初始化为1. * 2. 然后创建一个闭包, 闭包产生了对局部变量$counter的引用. * 3. 函数counter返回创建的闭包, 并销毁局部变量, 但此时有闭包对$counter的引用, * 它并不会被回收, 因此, 我们可以这样理解, 被函数counter返回的闭包, 携带了一个游离态的 * 变量. * 4. 由于每次调用counter都会创建独立的$counter和闭包, 因此返回的闭包相互之间是独立的. * 5. 执行被返回的闭包, 对其携带的游离态变量自增并返回, 得到的就是一个计数器. * 结论: 此函数可以用来生成相互独立的计数器. </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> counter() { </span><span style="color: #800080;">$counter</span> = 1<span style="color: #000000;">; </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">function</span>() <span style="color: #0000ff;">use</span>(&<span style="color: #800080;">$counter</span>) {<span style="color: #0000ff;">return</span> <span style="color: #800080;">$counter</span> ++<span style="color: #000000;">;}; } </span><span style="color: #800080;">$counter1</span> =<span style="color: #000000;"> counter(); </span><span style="color: #800080;">$counter2</span> =<span style="color: #000000;"> counter(); </span><span style="color: #0000ff;">echo</span> "counter1: " . <span style="color: #800080;">$counter1</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter1: " . <span style="color: #800080;">$counter1</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter1: " . <span style="color: #800080;">$counter1</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter1: " . <span style="color: #800080;">$counter1</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter2: " . <span style="color: #800080;">$counter2</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter2: " . <span style="color: #800080;">$counter2</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter2: " . <span style="color: #800080;">$counter2</span>() . "<br />/n"<span style="color: #000000;">; </span><span style="color: #0000ff;">echo</span> "counter2: " . <span style="color: #800080;">$counter2</span>() . "<br />/n"<span style="color: #000000;">; </span>?>
1. foreach ループのコードを削減します
たとえば、Cart
<?<span style="color: #000000;">php</span><span style="color: #008000;">//</span><span style="color: #008000;"> 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。// 其中有一个方法用来计算购物车中所有商品的总价格。该方法使用了一个closure作为回调函数。</span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Cart{ </span><span style="color: #0000ff;">const</span> PRICE_BUTTER = 1.00<span style="color: #000000;">; </span><span style="color: #0000ff;">const</span> PRICE_MILK = 3.00<span style="color: #000000;">; </span><span style="color: #0000ff;">const</span> PRICE_EGGS = 6.95<span style="color: #000000;">; </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$products</span> = <span style="color: #0000ff;">array</span><span style="color: #000000;">(); </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> add(<span style="color: #800080;">$product</span>, <span style="color: #800080;">$quantity</span><span style="color: #000000;">) { </span><span style="color: #800080;">$this</span>->products[<span style="color: #800080;">$product</span>] = <span style="color: #800080;">$quantity</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> getQuantity(<span style="color: #800080;">$product</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->products[<span style="color: #800080;">$product</span>]) ? <span style="color: #800080;">$this</span>->products[<span style="color: #800080;">$product</span>] : <span style="color: #0000ff;">FALSE</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> getTotal(<span style="color: #800080;">$tax</span><span style="color: #000000;">) { </span><span style="color: #800080;">$total</span> = 0.00<span style="color: #000000;">; </span><span style="color: #800080;">$callback</span> = <span style="color: #0000ff;">function</span> (<span style="color: #800080;">$quantity</span>, <span style="color: #800080;">$product</span>) <span style="color: #0000ff;">use</span> (<span style="color: #800080;">$tax</span>, &<span style="color: #800080;">$total</span><span style="color: #000000;">) { </span><span style="color: #800080;">$pricePerItem</span> = <span style="color: #008080;">constant</span>(<span style="color: #ff00ff;">__CLASS__</span> . "::PRICE_" . <span style="color: #008080;">strtoupper</span>(<span style="color: #800080;">$product</span><span style="color: #000000;">)); </span><span style="color: #800080;">$total</span> += (<span style="color: #800080;">$pricePerItem</span> * <span style="color: #800080;">$quantity</span>) * (<span style="color: #800080;">$tax</span> + 1.0<span style="color: #000000;">); }; </span><span style="color: #008000;">//</span><span style="color: #008000;">使用用户自定义函数对数组中的每个元素做回调处理</span> <span style="color: #008080;">array_walk</span>(<span style="color: #800080;">$this</span>->products, <span style="color: #800080;">$callback</span><span style="color: #000000;">); </span><span style="color: #0000ff;">return</span> <span style="color: #008080;">round</span>(<span style="color: #800080;">$total</span>, 2<span style="color: #000000;">);; }} </span><span style="color: #800080;">$my_cart</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Cart; </span><span style="color: #008000;">//</span><span style="color: #008000;"> 往购物车里添加条目</span><span style="color: #800080;">$my_cart</span>->add('butter', 1<span style="color: #000000;">);</span><span style="color: #800080;">$my_cart</span>->add('milk', 3<span style="color: #000000;">);</span><span style="color: #800080;">$my_cart</span>->add('eggs', 6<span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;"> 打出出总价格,其中有 5% 的销售税.</span><span style="color: #0000ff;">print</span> <span style="color: #800080;">$my_cart</span>->getTotal(0.05) . "\n"<span style="color: #000000;">;</span><span style="color: #008000;">//</span><span style="color: #008000;"> The result is 54.29</span>?>
2. 関数のパラメータを減らす
<span style="color: #0000ff;">function</span> html(<span style="color: #800080;">$code</span> , <span style="color: #800080;">$id</span>="", <span style="color: #800080;">$class</span>=""<span style="color: #000000;">){</span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$id</span> !== "") <span style="color: #800080;">$id</span> = " id = \"<span style="color: #800080;">$id</span>\""<span style="color: #000000;"> ;</span><span style="color: #800080;">$class</span> = (<span style="color: #800080;">$class</span> !== "")? " class =\"<span style="color: #800080;">$class</span>\">":">"<span style="color: #000000;">;</span><span style="color: #800080;">$open</span> = "<<span style="color: #800080;">$code$id$class</span>"<span style="color: #000000;">;</span><span style="color: #800080;">$close</span> = "</<span style="color: #800080;">$code</span>>"<span style="color: #000000;">;</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">function</span> (<span style="color: #800080;">$inner</span> = "") <span style="color: #0000ff;">use</span> (<span style="color: #800080;">$open</span>, <span style="color: #800080;">$close</span><span style="color: #000000;">){</span><span style="color: #0000ff;">return</span> "<span style="color: #800080;">$open$inner$close</span>"<span style="color: #000000;">; };}</span>
3. 再帰関数のロックを解除します
<?<span style="color: #000000;">php</span><span style="color: #800080;">$fib</span> = <span style="color: #0000ff;">function</span>(<span style="color: #800080;">$n</span>) <span style="color: #0000ff;">use</span>(&<span style="color: #800080;">$fib</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$n</span> == 0 || <span style="color: #800080;">$n</span> == 1) <span style="color: #0000ff;">return</span> 1<span style="color: #000000;">; </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$fib</span>(<span style="color: #800080;">$n</span> - 1) + <span style="color: #800080;">$fib</span>(<span style="color: #800080;">$n</span> - 2<span style="color: #000000;">);}; </span><span style="color: #0000ff;">echo</span> <span style="color: #800080;">$fib</span>(2) . "\n"; <span style="color: #008000;">//</span><span style="color: #008000;"> 2</span><span style="color: #800080;">$lie</span> = <span style="color: #800080;">$fib</span><span style="color: #000000;">;</span><span style="color: #800080;">$fib</span> = <span style="color: #0000ff;">function</span>(){<span style="color: #0000ff;">die</span>('error');};<span style="color: #008000;">//</span><span style="color: #008000;">rewrite $fib variable </span><span style="color: #0000ff;">echo</span> <span style="color: #800080;">$lie</span>(5); <span style="color: #008000;">//</span><span style="color: #008000;"> error because $fib is referenced by closure</span>
fib(n-1) が見つかりませんfunction ( fib のタイプは以前に定義されていませんでした) したがって、ループ関数をキャンセルするためにクロージャーを使用したい場合は、
。<?<span style="color: #000000;">php</span><span style="color: #800080;">$recursive</span> = <span style="color: #0000ff;">function</span> () <span style="color: #0000ff;">use</span> (&<span style="color: #800080;">$recursive</span><span style="color: #000000;">){</span><span style="color: #008000;">//</span><span style="color: #008000;"> The function is now available as $recursive</span>}
使用中の変数のバインドを遅らせる必要がある場合は、参照を使用する必要があります。そうしないと、定義時にコピーが作成されて使用されます
参照を使用するかどうかは、<?<span style="color: #000000;">php</span><span style="color: #800080;">$result</span> = 0<span style="color: #000000;">; </span><span style="color: #800080;">$one</span> = <span style="color: #0000ff;">function</span><span style="color: #000000;">(){ </span><span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$result</span><span style="color: #000000;">);}; </span><span style="color: #800080;">$two</span> = <span style="color: #0000ff;">function</span>() <span style="color: #0000ff;">use</span> (<span style="color: #800080;">$result</span><span style="color: #000000;">){ </span><span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$result</span><span style="color: #000000;">);}; </span><span style="color: #800080;">$three</span> = <span style="color: #0000ff;">function</span>() <span style="color: #0000ff;">use</span> (&<span style="color: #800080;">$result</span><span style="color: #000000;">){ </span><span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$result</span><span style="color: #000000;">);}; </span><span style="color: #800080;">$result</span>++<span style="color: #000000;">; </span><span style="color: #800080;">$one</span>(); <span style="color: #008000;">//</span><span style="color: #008000;"> outputs NULL: $result is not in scope</span><span style="color: #800080;">$two</span>(); <span style="color: #008000;">//</span><span style="color: #008000;"> outputs int(0): $result was copied</span><span style="color: #800080;">$three</span>(); <span style="color: #008000;">//</span><span style="color: #008000;"> outputs int(1)</span>