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

Dem*_*a ツ 54 php

根据有关变量变量的 PHP文档:

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

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

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

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

但还有更多.

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

它按预期停止执行:

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

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

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

但是(这是最奇怪的事情),明确引用特殊变量$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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Nik*_*kiC 70

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

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

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

现在考虑你的三种情况:

  1. $this并且${"this"}就PHP编译器而言是相同的(在两种情况下,在编译时都知道变量名称).
  2. 由于PHP 5.x编译器尚未执行常量表达式折叠,因此它也无法检测到这${"th"."is"}也是一种$this访问.所以this_var保持未初始化.
  3. 在最后一种情况下,您有一个简单的$this用法,因此this_var将设置并可通过变量查找进行访问.

请注意,PHP 7中的情况不同 - 我们将始终设置this_var变量查找,因此间接$this查找应始终有效.

  • @samyismyhero严肃地说,有太多人写了PHP6书籍,准备在2008年中止它(大部分是5.3版本).http://www.amazon.com/s/?url = search-alias%3Daps&field-keyword = PHP6 (4认同)
  • 用'APC`怎么样?这会折叠常量表达式,第二个例子会起作用吗? (2认同)