重新分配$ this时的有趣行为

时间:2012-07-10 14:38:37

标签: php class this

我调整了一个非常简单的View类来将变量从Controller传递到View,以便在View中我可以直接调用变量,例如。

<?php echo $name; ?>

而不是

<?php echo $this->name; ?>

所有视图变量都存储在名为vars的关联数组中,例如$vars['name'] = "test"并设置__set功能设置以分配变量,例如

$v = new View;
$v->name="test";
$v->out(); 

所以在传递变量的out()函数中包含我添加的视图HTML:

    foreach($this->vars as $key=>$val) {
      $$key=$val;
    }
include $this->view_file;

然后我测试了如果我在模板中使用$this并添加了相应的变量(如

)会发生什么
$v->this = "test_this";

我的假设是代码会失败,因为$this无法重新分配,或者即使重新分配 - see here - 代码也会失败,因为$this已被重新分配,所以

include $this->view_file;

不起作用!

相反,它起作用了。 $this,直接使用echo $this;var_dump($this);等于"test_this"直接调用,但$this->view_file仍指向原始值!!

这怎么可能?

然后我使用extract($this->vars, EXTR_OVERWRITE)重新测试,$this没有被触及!

通常,将变量传递给视图并避免函数中的冲突是正确的方法

function out($view, $toString = false)
{
    extract($this->vars);
    include $view;
}

和vars可能有一个名为view或“this”的var,或者模板可能会使用$view var。

  1. 别担心,只要确保不要分配名为view的视图。
  2. out()函数中使用长变量名称,例如$longVarNameSoThatThereWillNotBeCollisions
  3. 将函数所需的所有变量分配给$this->temp$this->temp['view']然后unset($view) - 以及$this - 正确思维的人将使用名为的变量$this中的View

2 个答案:

答案 0 :(得分:4)

要解释为什么您仍然能够访问对象属性,即使您已设法绕过重新分配$this的保护,您也必须查看为编译的脚本生成的操作码。

使用FETCH_OBJ_R操作码访问对象属性。

编写

等代码时
$myObject = new testClass;
$myObject->property

已编译的代码使用两个参数生成FETCH_OBJ_R。第一个是包含对象的变量,第二个是属性的名称。

如果使用Vulcan反汇编程序,输出可能如下所示:

FETCH_OBJ_R                                      $1      !1, 'property'

$1是存储返回值的地方,!1是包含该对象的变量。

但是,如果使用$this访问该属性,则生成的输出会略有不同。

FETCH_OBJ_R                                      $1      'property'

带有一个参数的操作码将属性查找解析为从中调用它的对象。

所以问题的答案$this->property在编译时得到了解决。即使您中断了$thisproperty的位置也已经确定。

答案 1 :(得分:0)

这让我感兴趣,看起来你是对的,使用变量赋值给$this时可能会出现错误。

正如你正确地说:

<?php
$var = 'this';
$$var = 'hello';

echo $this;

有效,而

<?php
$this = 'hello';

echo $this;

也许在bugs.php.net上报告,看看是否有正式答案?

$this的现有成员仍在工作,而$this的实际价值完全不同的事实绝对不应该发生,而且必须是某种形式的核心问题。我唯一能想到的是,不知怎的$this被用作神奇的上下文变量(当然不奇怪,它是PHP的后缀!)而不是真正的“真正的”变量。从变量变量赋值的错误(显然应该!)允许$this是一个虚假变量显示给开发人员的事实。

魔力测试:

<?php

class ThisTest {
    public function SetAndUseThis() {
        $var = 'this';
        $$var = 'that';
        var_dump($this);
        var_dump($this->variable);
        var_dump($this->AnotherMethod());
    }

    public $variable = 'i am a variable';

    public function AnotherMethod()
    {
        return 9.0;
    }
}

$inst = new ThisTest();
$inst->SetAndUseThis();

结果:

string(4) "that" string(15) "i am a variable" float(9)