本文实例讲述了PHP基于闭包思想实现的torrent文件解析工具。分享给大家供大家参考,具体如下:
PHP对静态词法域的支持有点奇怪,内部匿名函数必须在参数列表后面加上use关键字,显式的说明想要使用哪些外层函数的局部变量。
?
|
1
2
3
4
5
6
7
8
9
10
11
12
|
function count_down($count)
{
return $func = function()
use($count,$func)
{
if(--$count > 0)
$func();
echo "wow\\n";
};
}
$foo = count_down(3);
$foo();
|
我本来是想这样的。但是不行,会在第7行调用$func的时候报错。
错误是Fatal error: Function name must be a string in – on line 7
反复试验后发觉,外部的匿名函数应该通过引用传值传给内部,否则是不行的:
?
|
1
2
3
4
5
6
7
8
9
10
11
12
|
function count_down($count)
{
return $foo = function()
use(&$count,&$foo)
{
echo $count."\\n";
if(--$count > 0)
$foo();
};
}
$foo = count_down(4);
$foo();
|
像上面这样写就对了。
下面是另一种方法:
?
|
1
2
3
4
5
6
7
8
9
10
|
function count_down_again($count)
{
return function()use($count)
{
printf("wow %d\\n",$count);
return --$count;
};
}
$foo = count_down_again(5);
while($foo() >0);
|
不过,这段代码有点小错误。编译虽然没错,但是$foo函数每次返回的都是4.
也就是use关键字看上去像是支持静态词法域的,在这个例子上,它只是对外层函数使用的变量作了一个简单拷贝。
让我们稍微修改一下,把第3行的use($count)改为use(&$count):
?
|
1
2
3
4
5
6
7
8
9
10
|
function count_down_again($count)
{
return function()use(&$count)
{
printf("wow %d\\n",$count);
return --$count;
};
}
$foo = count_down_again(5);
while($foo() >0);
|
这样才正确。
我个人使用的方式是基于类的,做成了类似下面的形式:
?
|
1
2
3
4
5
6
7
8
9
10
11
|
class Foo
{
public function __invoke($count)
{
if($count > 0)
$this($count - 1);
echo "wow\\n";
}
}
$foo = new Foo();
$foo(4);
|
这样做的行为也是正确的。
这样不会像前一个例子那样失去了递归调用的能力。
虽然这是一个类,但是只不过是在手动实现那些支持闭包和静态词法域的语言中,编译器自动实现的动作。
其实今天早上,我本来准备用类scheme的风格写一个解析器的。可能稍微晚点吧。scheme风格的函数式编程是这样的:
?
|
1
2
3
4
5
6
7
|
function yet_another_count_down($func,$count)
{
$func($count);
if($count > 0)
yet_another_count_down($func,$count - 1);
}
yet_another_count_down(function($var){echo $var."\\n";},6);
|
它不是很依赖静态词法域,虽然scheme对静态词法域的支持还是很不错的。它主要还是利用了first-class-function。当然,这也是一种典型的闭包。
我实现的torrent解析工具的代码如下:
?
|
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
