PHP中的匿名函数

php从5.3开始加入了匿名函数的用法,下面我们就来看看这个匿名函数的一些用法

一:什么是闭包?

这个是我以前写的对闭包一些简单认识和使用,如果不是很了解闭包,可以先看看这篇文章中的例子: http://www.cnblogs.com/starlion/p/3894578.html

1:我听过一个说法:
所谓闭包,就是定义一段代码,同时对当时的运行上下文做一个快照,并捆绑在一起,用于在将来的某个时候让这段代码在当初的这个上下文中运行。个人感觉这个说法挺形象。

2:我觉得, 在php中需要改变一下这个说法:
在PHP中, 所谓闭包,就是定义一段代码,同时对当时的运行上下文有选择的做一个快照,并捆绑在一起,用于在将来的某个时候让这段代码在当初的选择上下文中运行。

二:匿名函数使用的场景

先看一个问题:来自 http://segmentfault.com/q/1010000000120409

1
2
3
4
5
6
7
8
9
10
$value = Session::get('key', 'default_value');
$value = Session::get('key', function(){ return'default_value';});

上面代码的意思就是根据session的key取得相应的值,
当该key相应的值不存在时,返回默认值(default_value)。
请问这两种写法有什么区别,
第一种很自然能理解,
第二种用匿名函数来返回的写法,有什么特定的使用场合吗?
请不吝赐教!
多谢!

答一:

问你一个问题就知道什么场合用匿名函数了:
假如默认值也是事先不知道,需要事后计算出来的呢?
当然你也可以在调用此方法之前先将默认值算好再传入第二参数,不过这样会有这么一个问题,如果key存在,并不需要默认值的情况下,之前算默认值运行的代码不是都浪费了吗?但是匿名函数不会,匿名函数的萌点在于需要调用它的时候才会运行,你只不过是事先定义好它的运行流程而已。
另外你这个题目有点不太准确,你正文里提到的问题其实跟闭包没什么关系哦

答二:

session中保存的值可能是字符串、数组、类等各种数据类型,就算是单一数据类型,它表示的意义也存在多种可能,如一本书信息,一个用户信息,一个销量排行等,除此之外,返回一个默认值还有可能要处理一些逻辑、事务等等
在这种情况下,将处理逻辑作为参数传入方法,可以方便的解决这类问题。

1
2
3
4
5
6
7
8
class Session
{

public static function get(String $key, Closure $func) {
// 取key的value,如果为空则调用匿名函数
return $func();
// 只专注于自己的业务(k-v),其它业务委托匿名函数处理。
}
}

匿名函数是不需要定义函数名的,可以作为参数传递给其他函数, 通常用于回调函数。

三:匿名函数使用

1:简单使用

1
2
3
4
5
$anonymous = function($str) {
echo $str;
};
$anonymous('Hello world!');
echo "<br>";

2:返回一个匿名函数和使用use传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//返回一个匿名函数
function close($a)
{

//匿名函数使用外部变量 用 use 关键字,具体这个close函数就是 $a, $a是匿名函数使用的外部变量
//调用匿名函数时候,给匿名函数传参? 跟平时我们的函数传参一样,具体这个就是 $b,也就是说 $b 是匿名函数持有的参数变量, 而 $a 是外部变量
return function($b) use($a) {
echo $a . '-' .$b . "\n";
};
}

//close() 函数有2个参数 $b 和 $a,我们怎么使用呢?
$c = close('a'); //调用close函数,并传递值 a 给函数close,函数close()返回值是一个匿名函数
$c('v'); //调用这个匿名函数,并且给匿名函数传递值 v, 就得到值 a-v

//我们打印下返回值 $c, 如下:
var_dump($c);

object(Closure)#2 (2) {
["static"]=>
array(1) {
["a"]=>
string(1) "a"
}
["parameter"]=>
array(1) {
["$b"]=>
string(10) "<required>"
}
}

//第二个使用 use 传参例子
$message = 'hello';
$example = function() use($message) {
var_dump($message);
};
$example(); // hello

$message = 'world';
$example = function($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example('hello'); //hello world

3:复杂的例子
来自: http://php.net/manual/en/functions.anonymous.php , 它上面运行时候报错,我修改了错误地方

这个例子利用动态调用函数 call_user_func() 函数, 把php的函数动态调用, 用匿名函数作为参数,类的调用和函数调用集成在一个 Event 事件类中了,
这是一个很好的集合,我们做一个容器,然后把函数的调用,类中函数的调用集合到这个容器中,需要使用函数或者方法的时候就到这个容器中去拿。现在好多框架都流行这种用法
call_user_func()的另外一个函数 call_user_func_array()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
class Event
{

public static $events = array();

public static function bind($event, $callback, $obj = null)
{

if(!isset(self::$events[$event]) || !self::$events[$event]) {
self::$events[$event] = array();
}
self::$events[$event][] = ($obj === null) ? $callback : array($obj, $callback);
}

public static function run($event)
{

if(!self::$events[$event]) return ;

foreach(self::$events[$event] as $callback) {
if(call_user_func($callback) === false) break;
}
}
}

function hello3() {
echo 'helo from function hello3' . "<br />\n";
}

class Foo {
function hello() {
echo 'hello from foo->hello() ' . "<br />\n";
}
}

class Bar {
static function hello() {
echo 'hello from Bar::hello()' . "<br />\n";
}
}

$foo = new Foo();

// bind a global function to the 'test' event
Event::bind('test', 'hello3');
// bind an anonymous function
Event::bind('test', function(){echo 'hello from anonymous function ' . "<br />";});
// bind an class function on an instance
Event::bind('test', 'hello', $foo);
// bind a static class function
Event::bind('test', "Bar::hello");

Event::run('test');
?>

4:最后一个复杂例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
class TheRoot
{

public function poidh($param) {
echo "the Root $param";
}
}

class Internet
{

public function run_my_closure($bar, Closure $my_closure) {//1.把参数 $bar 传递给匿名函数 $my_closure 了 2.把匿名函数当作参数传递
$my_closure($bar); //构造匿名函数, 我们还可以调用这个匿名函数
}
}

$Internet = new Internet();
$Root = new TheRoot();
//这个下面的调用我还不是很明白,匿名函数里面为什还能调用 $object->poidh(42); 这个, 怎么转换来的,虽然我给出了下面的解释,但是还不很明白
$Internet->run_my_closure($Root, function($object){ //有点DI(依赖注入)的思想, 匿名函数当作参数传递
$object->poidh(42);
});

//上面的 $Internet->run_my_closure 调用就相当于下面的匿名函数调用,这样来理解
echo "<br> ";
$clo = function($object) {
$object->poidh(42);
};
$clo($Root);
?>

http://ithelp.ithome.com.tw/question/10132747