怎么理解PHP5.5中迭代器与协程处理

怎么理解PHP5.5

yield特性

迭代器

1
2
3
4
5
6
7
8
9

Iterator extends Traversable {
/* 方法 */
abstract public mixed current ( void )//返回当前元素
abstract public scalar key ( void )//返回当前元素的键值
abstract public void next ( void )//向前移动到下一个元素
abstract public void rewind ( void )//返回到迭代器的第一个元素 重置指针
abstract public bool valid ( void )//检测当前元素有效性
}

//php 内置的迭代器

生成器

1
2
3
4
5
6
7
8
9
10
11
12
Generator implements Iterator {
public mixed current(void)
public mixed key(void)
public void next(void)
public void rewind(void)
// 向生成器传入一个值
public mixed send(mixed $value)
public void throw(Exception $exception)
public bool valid(void)
// 序列化回调
public void __wakeup(void)
}
白话解释
1
2
3
4
5
6
7
1. 生成器概念是php5.5以后引入的概念,是php5创新引入的一个新特性,但不是php语言特有的 像python也有迭代生成器的概念
2. 没有生成器以前要实现相似功能必须定义类实现Iterator接口,并实现其抽象方法 (稍微麻烦)
3. 引入生成器概念,使之上面的实现方式更简单,复杂性大大降低,并且可在foreach 代码块使用
4. php的操作核心是数组,如果数组过大则性能消耗或者内存占用就会很大甚至造成内存溢出
5. 生成器的语法 依赖 yield 关键字
6. 生成器函数实际上也是隐式的实现Iterator接口
7. 一个生成器不可以返回值: 这样做会产生一个编译错误。然而return空是一个有效的语法并且它将会终止生成器继续执行。
Demo 下面是模拟两个数组函数的和 opcode 信息
  • 普通函数在调用时候即执行 即 先灌满分配再遍历
  • 迭代器函数在调用时候并没有执行,而是生成一个可迭代的生成器对象(有点绕),是在遍历时候使用迭代对象时候才执行调用 即 所用即所得
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

/**
* User: wei
* Email:leo.yzw@foxmail.com
* Time: 14:45
*/


function (){
return range(1,10);
}

$nor = normal_array();

foreach ($nor as $v){
echo "$v t";
}


/**
php -dvld.active=1 -dvld.execute=1 create_array.php
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 77) Position 1 = 4, Position 2 = 11
Branch analysis from position: 4
Jump found. (Code = 78) Position 1 = 5, Position 2 = 11
Branch analysis from position: 5
Jump found. (Code = 42) Position 1 = 4
Branch analysis from position: 4
Branch analysis from position: 11
Jump found. (Code = 62) Position 1 = -2
Branch analysis from position: 11
filename: create_array.php
function name: (null)
number of ops: 13
compiled vars: !0 = $nor, !1 = $v
line #* E I O op fetch ext return opera
nds
--------------------------------------------------------------------------------
-----
9 0 E > NOP
13 1 DO_FCALL 0 $0 'norm
al_array'
2 ASSIGN !0, $
0
15 3 > FE_RESET $2 !0, -
>11
4 > > FE_FETCH $3 $2, -
>11
5 > OP_DATA
6 ASSIGN !1, $
3
16 7 ADD_VAR ~5 !1
8 ADD_STRING ~5 ~5, '
+%09'
9 ECHO ~5
17 10 > JMP ->4
11 > SWITCH_FREE $2
31 12 > RETURN 1

branch: # 0; line: 9- 15; sop: 0; eop: 3; out1: 4; out2: 11
branch: # 4; line: 15- 15; sop: 4; eop: 4; out1: 5; out2: 11
branch: # 5; line: 15- 17; sop: 5; eop: 10; out1: 4
branch: # 11; line: 17- 31; sop: 11; eop: 12; out1: -2
path #1: 0, 4, 5, 4, 11,
path #2: 0, 4, 11,
path #3: 0, 11,
Function normal_array:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename: create_array.php
function name: normal_array
number of ops: 5
compiled vars: none
line #* E I O op fetch ext return opera
nds
--------------------------------------------------------------------------------
-----
10 0 E > SEND_VAL 1
1 SEND_VAL 10
2 DO_FCALL 2 $0 'rang
e'
3 > RETURN $0
11 4* > RETURN null

branch: # 0; line: 10- 11; sop: 0; eop: 4
path #1: 0,
End of function normal_array

1 2 3 4 5 6 7 8 9 10


*/
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

/**
* User: wei
* Email:leo.yzw@foxmail.com
* Time: 14:45
*/

function gen_array(){
for($i=1;$i<=10;$i++){
yield $i;
}
}
$gen = gen_array();

foreach ($gen as $u){
echo "$u t";
}


/**

php -dvld.active=1 -dvld.execute=1 create_array2.php

Finding entry points
Branch analysis from position: 0
Jump found. (Code = 77) Position 1 = 4, Position 2 = 11
Branch analysis from position: 4
Jump found. (Code = 78) Position 1 = 5, Position 2 = 11
Branch analysis from position: 5
Jump found. (Code = 42) Position 1 = 4
Branch analysis from position: 4
Branch analysis from position: 11
Jump found. (Code = 62) Position 1 = -2
Branch analysis from position: 11
filename: create_array2.php
function name: (null)
number of ops: 13
compiled vars: !0 = $gen, !1 = $u
line #* E I O op fetch ext return opera
nds
--------------------------------------------------------------------------------
-----
8 0 E > NOP
13 1 DO_FCALL 0 $0 'gen_
array'
2 ASSIGN !0, $
0
15 3 > FE_RESET $2 !0, -
>11
4 > > FE_FETCH $3 $2, -
>11
5 > OP_DATA
6 ASSIGN !1, $
3
16 7 ADD_VAR ~5 !1
8 ADD_STRING ~5 ~5, '
+%09'
9 ECHO ~5
17 10 > JMP ->4
11 > SWITCH_FREE $2
20 12 > RETURN 1

branch: # 0; line: 8- 15; sop: 0; eop: 3; out1: 4; out2: 11
branch: # 4; line: 15- 15; sop: 4; eop: 4; out1: 5; out2: 11
branch: # 5; line: 15- 17; sop: 5; eop: 10; out1: 4
branch: # 11; line: 17- 20; sop: 11; eop: 12; out1: -2
path #1: 0, 4, 5, 4, 11,
path #2: 0, 4, 11,
path #3: 0, 11,
Function gen_array:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 45) Position 1 = 8, Position 2 = 6
Branch analysis from position: 8
Jump found. (Code = 161) Position 1 = -2
Branch analysis from position: 6
Jump found. (Code = 42) Position 1 = 3
Branch analysis from position: 3
Jump found. (Code = 42) Position 1 = 1
Branch analysis from position: 1
filename: create_array2.php
function name: gen_array
number of ops: 9
compiled vars: !0 = $i
line #* E I O op fetch ext return opera
nds
--------------------------------------------------------------------------------
-----
9 0 E > ASSIGN !0, 1

1 > IS_SMALLER_OR_EQUAL ~1 !0, 1
0
2 > JMPZNZ 6 ~1, -
>8
3 > POST_INC ~2 !0
4 FREE ~2
5 > JMP ->1
10 6 > YIELD !0
11 7 > JMP ->3
12 8 > > GENERATOR_RETURN

branch: # 0; line: 9- 9; sop: 0; eop: 0; out1: 1
branch: # 1; line: 9- 9; sop: 1; eop: 2; out1: 8; out2: 6
branch: # 3; line: 9- 9; sop: 3; eop: 5; out1: 1
branch: # 6; line: 10- 11; sop: 6; eop: 7; out1: 3
branch: # 8; line: 12- 12; sop: 8; eop: 8; out1: -2
path #1: 0, 1, 8,
path #2: 0, 1, 6, 3, 1, 8,
End of function gen_array

1 2 3 4 5 6 7 8 9 10



*/

协程

1
2
3
4
5
协程的支持是在迭代生成器的基础上,
增加了可以回送数据给生成器的功能
(调用者发送数据给被调用的生成器函数).
这就把生成器到调用者的单向通信转变为两者之间的双向通信.
传递数据的功能是通过迭代器的send()方法实现的

Generator::send(mixed $value)
向生成器中传入一个值,并且当做yield表达式的结果,然后继续执行生成器。
如果当这个方法被调用时,生成器不在 yield 表达式,那么在传入值之前,它会先运行到第一个 yield 表达式。

image

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


function test()
{
$a = (yield 111);
echo 'test()->$a:'.$a.PHP_EOL;
$b = (yield 222);
echo 'test()->$b:'.$b.PHP_EOL;
}
$gen = test();
var_dump($gen);
echo "第一次:#".PHP_EOL;
var_dump($gen->current());
echo "第二次:#".PHP_EOL;
var_dump($gen->send(333));
echo "第三次:#".PHP_EOL;
var_dump($gen->next());

/*** output
$ php diedai.php
object(Generator)#1 (0) {
}
第一次:#
int(111)
第二次:#
test()->$a:333
int(222)
第三次:#
test()->$b:
NULL


*/

?>

参考文档#php.net

参考文档#PHP中使用协程实现多任务调度