クロージャ採用ですって!
http://news.php.net/php.cvs/50908
うっはー信じられぬ。
ざっと見たところ、大抵のことは出来てる模様。
コンパイル時のテスト内容を引用して、仕様を確認してみる。
- Closure 001: Lambda without lexical variables
- Closure 002: Lambda with lexical variables (global scope)
- Closure 003: Lambda with lexical variables (local scope)
- Closure 004: Lambda with lexical variables (scope lifetime)
- Closure 005: Lambda inside class, lifetime of $this
- Closure 006: Nested lambdas
- Closure 007: Nested lambdas in classes
- Closure 008: Use in preg_replace()
- Closure 009: Use in preg_replace()
- Closure 010: Closure calls itself
- Closure 011: Lexical copies not static in closure
- Closure 012: Undefined lexical variables
Closure 001: Lambda without lexical variables
レキシカル変数を含まないラムダ式。
$lambda = function () {}; は、ちゃんと is_callable($lambda) == true になるみたい。
call_user_func($lambda, $some_variable); も動く。
<?php $lambda1 = function () { echo "Hello World!\n"; }; $lambda2 = function ($x) { echo "Hello $x!\n"; }; var_dump(is_callable($lambda1)); var_dump(is_callable($lambda2)); $lambda1(); $lambda2("Universe"); call_user_func($lambda1); call_user_func($lambda2, "Universe"); echo "Done\n"; ?>
bool(true) bool(true) Hello World! Hello Universe! Hello World! Hello Universe! Done
Closure 002: Lambda with lexical variables (global scope)
レキシカル変数を含むラムダ式のうち、そのレキシカル変数がグローバルスコープだった場合。
use() を使う。
use($lexical) だと、定義時の変数をコピーする?
use(&$lexical) だと、定義時の変数にリファレンスを張る?
<?php $x = 4; $lambda1 = function () use ($x) { echo "$x\n"; }; $lambda2 = function () use (&$x) { echo "$x\n"; }; $lambda1(); $lambda2(); $x++; $lambda1(); $lambda2(); echo "Done\n"; ?>
4 4 4 5 Done
Closure 003: Lambda with lexical variables (local scope)
レキシカル変数を含むラムダ式のうち、そのレキシカル変数がローカルスコープだった場合。
同様に動く。
<?php function run () { $x = 4; $lambda1 = function () use ($x) { echo "$x\n"; }; $lambda2 = function () use (&$x) { echo "$x\n"; }; $lambda1(); $lambda2(); $x++; $lambda1(); $lambda2(); } run(); echo "Done\n"; ?>
4 4 4 5 Done
Closure 004: Lambda with lexical variables (scope lifetime)
ローカルスコープのレキシカル変数を含むラムダ式は、そのスコープを抜けても生きている。
<?php function run () { $x = 4; $lambda1 = function () use ($x) { echo "$x\n"; }; $lambda2 = function () use (&$x) { echo "$x\n"; $x++; }; return array($lambda1, $lambda2); } list ($lambda1, $lambda2) = run(); $lambda1(); $lambda2(); $lambda1(); $lambda2(); echo "Done\n"; ?>
4 4 4 5 Done
Closure 005: Lambda inside class, lifetime of $this
ラムダ式の中に $this が入っていた場合の、オブジェクトの生存期間。
$this を持つラムダ式が全部消えたら消える。
まあ普通よね。
static function () {}; は、 $this を持つラムダ式とはカウントされない。
<?php class A { private $x; function __construct($x) { $this->x = $x; } function __destruct() { echo "Destroyed\n"; } function getIncer($val) { return function() use ($val) { $this->x += $val; }; } function getPrinter() { return function() { echo $this->x."\n"; }; } function getError() { return static function() { echo $this->x."\n"; }; } function printX() { echo $this->x."\n"; } } $a = new A(3); $incer = $a->getIncer(2); $printer = $a->getPrinter(); $error = $a->getError(); $a->printX(); $printer(); $incer(); $a->printX(); $printer(); unset($a); $incer(); $printer(); unset($incer); $printer(); unset($printer); $error(); echo "Done\n"; ?>
3 3 5 5 7 7 Destroyed Fatal error: Using $this when not in object context in %sclosure_005.php on line 28
Closure 006: Nested lambdas
ネストできるよ!
<?php $getClosure = function ($v) { return function () use ($v) { echo "Hello World: $v!\n"; }; }; $closure = $getClosure (2); $closure (); echo "Done\n"; ?>
Hello World: 2! Done
Closure 007: Nested lambdas in classes
ネストできるよ!!
<?php class A { private $x = 0; function getClosureGetter () { return function () { return function () { $this->x++; }; }; } function printX () { echo $this->x."\n"; } } $a = new A; $a->printX(); $getClosure = $a->getClosureGetter(); $a->printX(); $closure = $getClosure(); $a->printX(); $closure(); $a->printX(); echo "Done\n"; ?>
0 0 0 1 Done
Closure 008: Use in preg_replace()
preg_replace() で使いたくなるよね、やっぱり。
<?php function replace_spaces($text) { $lambda = function ($matches) { return str_replace(' ', ' ', $matches[1]).' '; }; return preg_replace_callback('/( +) /', $lambda, $text); } echo replace_spaces("1 2 3\n"); echo replace_spaces("1 2 3\n"); echo replace_spaces("1 2 3\n"); echo "Done\n"; ?>
1 2 3 1 2 3 1 2 3 Done
Closure 009: Use in preg_replace()
preg_replace() その 2 。
<?php $a = 1; $x = function ($x) use ($a) { static $n = 0; $n++; $a = $n.':'.$a; echo $x.':'.$a."\n"; }; $y = function ($x) use (&$a) { static $n = 0; $n++; $a = $n.':'.$a; echo $x.':'.$a."\n"; }; $x(1); $x(2); $x(3); $y(4); $y(5); $y(6); ?>
1:1:1 2:2:1 3:3:1 4:1:1 5:2:1:1 6:3:2:1:1
Closure 010: Closure calls itself
$lambda = function () { $lambda(); }; はできないのね。
スコープ的におかしいし、これで良し。
<?php $i = 3; $lambda = function ($lambda) use (&$i) { if ($i==0) return; echo $i--."\n"; $lambda($lambda); }; $lambda($lambda); echo "$i\n"; ?>
3 2 1 0
Closure 011: Lexical copies not static in closure
以前のプロトタイプだとおかしかったけど、今はもう大丈夫、ってさ。
<?php $i = 1; $lambda = function () use ($i) { return ++$i; }; $lambda(); echo $lambda()."\n"; //early prototypes gave 3 here because $i was static in $lambda ?>
2
Closure 012: Undefined lexical variables
未定義の変数使うと訳分からなくなるよ!
<?php $lambda = function () use ($i) { return ++$i; }; $lambda(); $lambda(); var_dump($i); $lambda = function () use (&$i) { return ++$i; }; $lambda(); $lambda(); var_dump($i); ?>
Notice: Undefined variable: i in %sclosure_012.php on line 2 Notice: Undefined variable: i in %sclosure_012.php on line 7 NULL int(2)