クロージャ
クロージャとは関数の一種で、
クロージャは関数がアクセス可能な変数が、
クロージャの使い方
クロージャはラムダ関数、
クロージャに慣れていない方は、
クロージャの構文は次のように、
- 無名関数の構文
- function( [ 引数 ] ... ) { 文 };
PHP以外の言語では、
無名関数の中から無名関数が実行されるスコープ内の変数を使用する場合には、
- use文を利用する場合の無名関数の構文
- funciton( [ 引数 ] ... ) use ( [ 変数 ] ... ) { 文 };
多少面倒に思うかも知れませんが、
無名関数は関数名が無いので、
<?php
$writeline = function($msg) { echo $msg.PHP_EOL; };
$writeline('ABC');
$writeline('XYZ');
?>
ABC XYZ
これだけでは何が便利なのかさっぱり分からないですが、
function($msg) { echo $msg.PHP_EOL; };
の部分が無名関数の定義です。無名関数は直接パラメータとしてほかの関数に渡すことが出来ます。
<?php
$fruits = array("lemon"=>156, "orange"=>210, "banana"=>180, "apple"=>343);
array_walk($fruits,function($price,$name) { echo $name.':'.$price.PHP_EOL; });
?>
lemon:156 orange:210 banana:180 apple:343
無名関数が無いPHP 5.
function($price,$name) { echo $name.':'.$price.PHP_EOL;}
を別の関数として定義した上で、
<?php
$fruits = array("lemon"=>156, "orange"=>210, "banana"=>180, "apple"=>343);
function callback($price,$name) { echo $name.':'.$price.PHP_EOL; }
array_walk($fruits,'callback');
?>
あまり、
無名関数を使うと、
<?php
$square = function($x) { return ($x * $x); };
$increment = function($x) { return ++$x; };
function foo($param, $op) {
return $op($param);
}
echo foo(3, $square) . PHP_EOL;
echo foo(4, $increment) . PHP_EOL;
?>
変数関数に書き換えると次のようになります。
<?php
function square($x) { return ($x * $x); }
function increment($x) { return ++$x; };
function foo($param, $op) {
return $op($param);
}
echo foo(3, 'square') . PHP_EOL;
echo foo(4, 'increment') . PHP_EOL;
?>
どちらも全く同じことができますが、
‘square_
また、
<?php
$arr = array(
array(12,33,1),
array(21,2,105),
array(3,99,3),
);
$elem = 1;
uasort($arr, function($x, $y) use ($elem)
{
if ($x[$elem] == $y[$elem]) return 0;
return (($x[$elem] < $y[$elem]) ?-1 : 1);
}
);
print_r($arr);
?>
Array ( [1] => Array ( [0] => 21 [1] => 2 [2] => 105 ) [0] => Array ( [0] => 12 [1] => 33 [2] => 1 ) [2] => Array ( [0] => 3 [1] => 99 [2] => 3 ) )
この例では多次元配列ですが、
次はよりクロージャの便利さが分かる、
<?php
function sum_includes_tax($items, $tax) {
$total = 0;
array_walk($items,
function($price,$name) use (&$total, $tax)
{
echo $name.':'.$price.'('.(int)($price*$tax).')'.PHP_EOL;
$total += ($price+(int)($price*$tax));
}
);
return $total;
}
$items = array("lemon"=>100, "orange"=>200, "banana"=>300, "apple"=>400);
$total = sum_includes_tax($items, 0.05);
echo 'TOTAL:'.$total.PHP_EOL;
?>
lemon:100(5) orange:200(10) banana:300(15) apple:400(20) TOTAL:1050
PHPはクロージャ
<?php
function print_elem($price, $name, &$user_data) {
echo $name.':'.$price.'('.(int)($price*$user_data['tax']).')'.PHP_EOL;
$user_data['total'] += ($price+(int)($price*$user_data['tax']));
}
function sum_includes_tax($items, $tax) {
$user_data['total'] = 0;
$user_data['tax'] = $tax;
array_walk($items,'print_elem', $user_data);
return $user_data['total'];
}
$items = array("lemon"=>100, "orange"=>200, "banana"=>300, "apple"=>400);
$total = sum_includes_tax($items, 0.05, $user_data);
echo 'TOTAL:'.$total.PHP_EOL;
?>
実はこのコードではクロージャを利用した例のように動作しません。コールバック関数のuser_
lemon:100(5) orange:200(10) banana:300(15) apple:400(20) TOTAL:0
クロージャ
クロージャ
制限付きgoto文
PHPにはプログラムの実行を自由な場所に移動するgoto文がサポートされていませんでした。goto文の乱用は簡単に理解不能なプログラムを作ってしまうからです。
しかし、
Visual Baiscでプログラミングをした経験がある方であれば、
goto文の使い方
- 構文
- goto ラベル;
goto文の使い方は説明するまでもないと思います。以下にサンプルコードを書いておきます。
<?php
goto A;
echo 'skipped';
A:
?>
<?php
goto A;
B:
die('stupid code');
A:
goto B;
?>
<?php
goto A;
for ($i=0; $i<10; $i++) {
echo $i;
A:
}
?>
Fatal error: 'goto' into loop or switch statement is disallowed in /home/yohgaki/ext/src/php/php-5.3.0/e2.php on line 2
<?php
for ($i=0; $i<10; $i++) {
echo $i;
if ($i == 5) goto A;
}
A:
?>
012345
goto文によりコードが大幅に読みやすくなる場合以外は極力利用しないようにするほうが良いでしょう。上の例のような単純にループから抜け出る場合は、
<?php
for ($i=0; $i<10; $i++) {
echo $i;
if ($i == 5) break;
}
?>
ループ処理の例外処理はほとんどの場合、
次回はPHP 5.