8

我试图理解一个简单代码的操作码。

代码是:

<?php

$a = TRUE;

$b = FALSE;

if($a && $b) {
    echo 'done';
}

上述代码的操作码为:

php -dvld.active=1 test.php
Finding entry points
Branch analysis from position: 0
Jump found. Position 1 = 3, Position 2 = 4
Branch analysis from position: 3
Jump found. Position 1 = 5, Position 2 = 7
Branch analysis from position: 5
Jump found. Position 1 = 7
Branch analysis from position: 7
Return found
Branch analysis from position: 7
Branch analysis from position: 4
filename:       /home/starlays/learning/test.php
function name:  (null)
number of ops:  8
compiled vars:  !0 = $a, !1 = $b
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   3     0  >   ASSIGN                                                   !0, true
   5     1      ASSIGN                                                   !1, false
   7     2    > JMPZ_EX                                          ~2      !0, ->4
         3  >   BOOL                                             ~2      !1
         4  > > JMPZ                                                     ~2, ->7
   8     5  >   ECHO                                                     'done'
   9     6    > JMP                                                      ->7
  10     7  > > RETURN                                                   1

branch: #  0; line:     3-    7; sop:     0; eop:     2; out1:   3; out2:   4
branch: #  3; line:     7-    7; sop:     3; eop:     3; out1:   4
branch: #  4; line:     7-    7; sop:     4; eop:     4; out1:   5; out2:   7
branch: #  5; line:     8-    9; sop:     5; eop:     6; out1:   7
branch: #  7; line:    10-   10; sop:     7; eop:     7
path #1: 0, 3, 4, 5, 7, 
path #2: 0, 3, 4, 7, 
path #3: 0, 4, 5, 7, 
path #4: 0, 4, 7, 

我试图了解第 7 行发生了什么,评估是如何完成的?它在 if 的表达式中输入了多少值进行评估?它输入 3 个值,还是输入 2 个值 $a 的值和 $b 的值,然后计算 if 括号中的表达式?

我已经阅读了 JMPZ_EX的手册,我已经了解操作代码中发生的事情,直到步骤 2 之后有点混淆,我很难理解 php 正在执行的确切步骤。

我需要了解的另一件事是操作代码中的所有分支是什么,最后将使用所有分支中的哪一个?

4

2 回答 2

2

除非您精通ASM,否则我认为了解正在发生的事情的最简单方法是通过阅读其在 PHP 中的(几乎)1:1 表示来查看相同的代码:

if(!$a) goto end;
if(!$b) goto end;
echo 'done';
end: return 0;

中间表示基于实际子句的否定来跳过if块中包含的代码。

如果您想真正了解 PHP 如何将其输入转换为该操作码数组,则必须了解 PHP 内部原理,但不要在学习龙书之前,特别是关于中间表示的部分,它是编译管道的一部分。

其余的操作码是“背景噪音”、中间值,甚至是一条毫无意义的指令,9 6 > JMP ->7这可能是因为努力让 PHP 解析器吐出最佳操作码数组是没有意义的要运行的 ZendVM。

于 2012-07-23T15:46:37.450 回答
2
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   3     0  >   ASSIGN                                                   !0, true
   5     1      ASSIGN                                                   !1, false
   7     2    > JMPZ_EX                                          ~2      !0, ->4
         3  >   BOOL                                             ~2      !1
         4  > > JMPZ                                                     ~2, ->7
   8     5  >   ECHO                                                     'done'
   9     6    > JMP                                                      ->7
  10     7  > > RETURN                                                   1

按行号#

0 assigns true to !0, !0 is just the internal representation of $A
1 assigns true to !1, !1 is $B

JMPZ 表示如果值为 0,则跳转到代码。我不确定 JMPZ_EX 的具体区别,它看起来允许返回布尔结果。

所以:

2 JMPZ_EX, Jump to #4 (->4) if !0 ($A) is 0 (FALSE) and assign the result to ~2

3 BOOL !1 return ~2. ~2 is now equal to the BOOLean value of !1 ($B)
4 JMPZ ~2, Jump to #7 if ~2 is zero

5 ECHO, our echo statement. If any of the JMPZ had jumped, this part would be skipped.
6 JMP -7, jumps to #7
7 RETURN, ends the function call

一些注意事项:

  • 在这种情况下,JMPZ_EX 似乎是不必要的,但在需要使用该值来计算更多值的更复杂的 if 语句中会很有用。
  • 6 JMP -7 可能在那里允许一个 else 块。如果这是 if 块的主要部分,完成它然后可以跳过作为 else 块的代码部分。
于 2012-07-23T16:08:12.033 回答