动态引用$ this应该不起作用,但确实如此

时间:2015-02-09 21:40:38

标签: php

根据关于Variable variables的PHP文档:

  

$这是一个无法动态引用的特殊变量

然而,似乎它是假的,至少在PHP版本上,我已经测试过(5.5.12)。

class ThisIsBugged
{
    public function __construct()
    {
        ${'this'}->doSomething(); // This works, while it shouldn't
    }
}

问题#1 :它如何运作?根据文件,它不应该。

但还有更多。

class ThisIsBugged
{
    public function __construct()
    {
        // This does not work, but it could. See below.
        ${'th' . 'is'}->doSomething();
    }
}

它按预期停止执行:

  

PHP注意:未定义的变量:这个

     

PHP致命错误:在a上调用成员函数doSomething()   非对象。

请注意,语句{'th' . 'is'}已经过评估:"未定义变量:此"

然而(这是最奇怪的事情),明确引用特殊变量$this,修复了方法之前或之后使用的所有动态引用。

class ThisIsBugged
{
    public function __construct()
    {
        // Now it works while it shouldn't
        ${'th' . 'is'}->doSomething();

        // This fixes both the previous and the subsequent calls
        $unused = $this;

        // Now it works while it shouldn't
        ${'th' . 'is'}->doSomething();
    }
}

问题#2 :对$this的明确引用如何修复整个方法中存在的$this的所有其他动态引用?

1 个答案:

答案 0 :(得分:70)

PHP使用我们称之为编译变量(CV)优化的概念。这意味着我们不使用将变量名称映射到其值的哈希表,而是使用普通数组并将其索引到其中。编译器知道哪个变量名对应于哪个索引。执行数组索引查找比执行哈希表查找要快得多。

$this变量也将以这种方式存储,其索引特别记为op_array->this_var。如果未找到$this使用,则此值在-1处未初始化。将新的执行上下文推送到VM堆栈时,PHP将检查op_array->this_var,如果不是-1,则初始化$this变量条目。

当访问变量变量时,PHP将遍历CV表并从中构造一个正确的符号哈希表。当然它只会添加CV表中实际存在的变量,所以如果它不包含$this,你最终会得到一个未定义的变量查找。

现在考虑你的三个案例:

    就li编译器而言,
  1. $this${"this"}是相同的(在编译时都知道所有变量名称)。
  2. 由于PHP 5.x编译器尚未执行常量表达式折叠,因此它无法检测到${"th"."is"}$this访问权限。因此this_var保持未初始化状态。
  3. 在最后一种情况下,您使用普通$this,因此this_var将被设置,并且也可以通过变量查找进行访问。
  4. 请注意,PHP 7中的情况不同 - 我们总是在变量查找上设置this_var,因此间接$this查找应该始终有效。