为什么isset()和empty()使用相同的opcode?

10

如果isset()empty()生成了完全相同的ISSET_ISEMPTY_DIM_OBJ操作码,那么PHP虚拟机如何区分这两者?

以下是代码:

empty($a['b']);
isset($a['b']);

生成以下操作码:

ISSET_ISEMPTY_DIM_OBJ $a, b -> TMP_VAR 0
FREE TMP_VAR 0

ISSET_ISEMPTY_DIM_OBJ $a, b -> TMP_VAR 1
FREE TMP_VAR 1

另一个测试:

if (empty($a['b'])) {
    echo 'abc';
}

if (isset($a['b'])) {
    echo 'abc';
}

这会产生:

ISSET_ISEMPTY_DIM_OBJ $a, b -> TMP_VAR 0
JMPZ TMP_VAR 0, &(BC4E00+4)
ECHO abc
JMP &(BC4E00+4)

ISSET_ISEMPTY_DIM_OBJ $a, b -> TMP_VAR 1
JMPZ TMP_VAR 1, &(BC4FE0+8)
ECHO abc
JMP &(BC4FE0+8)

4
你怎么能到达这个水平的,哈哈。 - dynamic
这可能是某些优化的结果。您没有使用返回值。尝试一些更复杂的东西,比如 if (…) - Gumbo
我还尝试对这两个函数的结果使用var_dump(),以查看是否isset()现在确切地执行了empty()的功能,但是结果一个为true,另一个为false,而且它们的操作码完全相同... - rid
2个回答

6
无论您使用什么工具来创建该opcode转储,它只告诉了您其中一半的真相:它忘记了PHP根据使用的语言结构向该opcode传递常量。这些常量是ZEND_ISEMPTY用于emptyZEND_ISSET用于isset
您可以在此处找到调用herehere。(并且here类型被放入opcode的extended_value中。)
如果您查看full opcodes,您将会在ext列中看到那些常量作为1ZEND_ISSET = (1<<0))和2ZEND_ISEMPTY = (1<<1))。

4

你是怎么得到这些操作码的?

我使用"Bytekit"运行了你的代码片段,得到了以下输出:

Function:           main
Number of oplines:  5
Compiled variables: !0 = $a

  line  #     opcode                           result  operands
  -----------------------------------------------------------------------------
  3     0     ISEMPTY_DIM_OBJ                  ~0      !0, 'b'
        1     FREE                                     ~0
  4     2     ISSET_DIM_OBJ                    ~1      !0, 'b'
        3     FREE                                     ~1
  6     4     RETURN                                   1

所以,在这种情况下,操作码是有区别的。唯一的问题是,我似乎在官方PHP网站上找不到“我的”操作码。这让我感到困惑,因为迄今为止,bytekit已经证明是一个很好的工具。
我会研究一下,但与此同时,我认为你可能会发现我当前的输出有价值。
顺便说一下,我正在Ubuntu上运行PHP 5.3.3。

这一定是因为 PHP 版本的问题。我正在使用 PHP 5.3.4。 - rid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接