PHP中的if语句和switch语句生成的opcode对比
我们有如下测试脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
$variable = 1;
if ($variable == 1) { var_dump($variable); } else if ($variable == 2) { var_dump($variable); } else if ($variable == 3) { var_dump($variable); }
var_dump(4);
|
生成的opcodes
如下:
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
| [Stack in /root/codeDir/phpCode/test/test.php (22 ops)] L1-14 {main}() /root/codeDir/phpCode/test/test.php - 0x7fdcaca80000 + 22 ops L3 L5 L5 L6 L6 L6 L6 L7 L7 L8 L8 L8 L8 L9 L9 L10 L10 L10 L13 L13 L13 L14 prompt>
|
我们来看PHP
代码分别对应的opcodes
(我没有完全按照基本块来划分,只是简单的按照代码结构来划分):
第一段:
第二段:
1 2 3 4 5 6 7 8 9 10
| if ($variable == 1) { var_dump($variable); }
L5 L5 L6 L6 L6 L6
|
第三段:
1 2 3 4 5 6 7 8 9 10
| else if ($variable == 2) { var_dump($variable); }
L7 L7 L8 L8 L8 L8
|
第四段:
1 2 3 4 5 6 7 8 9
| else if ($variable == 3) { var_dump($variable); }
L9 L9 L10 L10 L10
|
第五段:
1 2 3 4 5 6
| var_dump(4);
L13 L13 L13 L14
|
我们会发现,这里的IS_EQUAL ... JMPZ
是分布在每一个块里面的。
我们翻译成对应的switch
语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
$variable = 1; switch ($variable) { case 1: var_dump($variable); break; case 2: var_dump($variable); break; case 3: var_dump($variable); break; } var_dump(4);
|
对应的opcodes
如下:
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
| [Stack in /root/codeDir/phpCode/test/test.php (24 ops)] L1-15 {main}() /root/codeDir/phpCode/test/test.php - 0x7f7780480000 + 24 ops L3 L5 L5 L8 L8 L11 L11 L11 L6 L6 L6 L7 L9 L9 L9 L10 L12 L12 L12 L13 L15 L15 L15 L15
|
我们可以稍微划分一下。
第一段:
第二段,所有的switch ... case
组成一段:
1 2 3 4 5 6 7 8 9
| switch ... case
L5 L5 L8 L8 L11 L11 L11
|
第三段,我们可以把所有case
里面的语句组成一段:
1 2 3 4 5 6 7 8 9 10 11 12
| L6 L6 L6 L7 L9 L9 L9 L10 L12 L12 L12 L13
|
第四段:
1 2 3 4 5 6
| var_dump(4);
L15 L15 L15 L15
|
我们会发现,switch ... case
有一种map
的感觉。无论有多少个case
,我们这里都可以把switch ... case
和case
里面的语句划分成两部分。但是,如果是if ... else
的话,随着分支的增加,段的数目也会跟着增加(再次提醒,我没有按照基本块来划分,因为按照基本块来划分,每一个case
里面的语句都算一个基本块)。
那么,为什么我不把第一个脚本的代码里面的if ... else
也划成一大段呢?因为我们会发现,如果我们划成一大段,JMP
会在这一个大段里面跳来跳去。所以,我们也会发现,实际上,switch ... case
是把if ... else
的跳转关系集中放到了一块,而if ... else
的跳转关系放在了每一个小段里面。
我们可以用如下流程图来描述这两种结构:
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
| +----------------+ | if | | | +----------------+ | | | | v +----------------+ | else if | | | +----------------+ | | | v +----------------+ | else | | | +----------------+
+-------------------------+ | switch | | | +-------------------------+ | | +--------------------+--------------------+ | | | v v v +----------------+ +----------------+ +----------------+ | case | | case | | case | | | | | | | +----------------+ +----------------+ +----------------+
|