诡异的php变量名

来源:互联网 发布:mac怎么关掉死机程序 编辑:程序博客网 时间:2024/05/09 08:04

在类的方法中,$this关键字用来指向当前类的对象实例,如果对$this进行赋值操作,会发生什么事情?

<?php  
class Person  
{  
    protected $_name = "phper";  
  
    protected $_age  = 18;  
  
    public function getName()  
    {  
        $this = 123;  
        return $this->_name;  
    }  
  
    public function getAge()  
    {  
        return $this->_age;  
    }  
}  
  
  
$p = new Person();  
$p->getName();  
?>  

执行代码,报错:

1Fatal error: Cannot re-assign $this in...
PHP对$this变量做了一定保护措施,但是这个保护措施也不是完全的,我们利用前面的方法在执行期改变$this的值, 修改后的getName方法为:

public function getName()  
{  
    $a = "this";  
    $$a = 123;  
    echo $this;  
    return $this->_name;  
}  

然后执行代码,发现能够顺利执行,$this的值变成了123, 由此可以判断对$this关键字的保护也仅限与语法分析阶段。

当$this的值变成123之后,按理说$this->_name肯定会报错的,但是居然代码能正常执行,这个确实很让人觉得不可思议。于是推断 $this->_name这样的引用方式和一般的对象变量引用方式在有差异,我们继续对getName做修改:


public function getName()  
{  
    $a = "this";  
    $$a = 123;  
    $b = 123;  
    echo $this;  
    echo $b;  
    $this->getAge();  
    $b->getAge();  
    return $this->_name;  
}

这段代码中,$this和$b的值都等于123,但是$this->getAge()可以顺利执行,$b->getAge()却报错:Fatal error: Call to a member function getAge() on a non-object...

这是一个诡异的问题,于是可以推断$this->getAge()和$b->getAge()在编译之后对应的op handler肯定有所差异,于是查看之。

通过vld查看op的信息:

  • $this->getAge()对应的为: ZEND_INIT_METHOD_CALL    RES[  IS_UNUSED  ]         OP1[  IS_UNUSED  ] OP2[  IS_CONST (8142027) 'getAge' ]
  • $b->getAge()在对应的为: ZEND_INIT_METHOD_CALL    RES[  IS_UNUSED  ]         OP1[  IS_CV !0 ]      OP2[ ,  IS_CONST (8142039) 'getAge' ]

虽然对应了同样的op code,但是由于操作数的不同(前者不使用OP1,后者使用OP1, 且OP1的值!0表示$b),同一个op code对应同一类handler,然后根据操作数的类型确定到此类handler中的某一个handler。

  • $this->getAge()对应的handler处理为:ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER
  • $b->getAge()    对应的handler处理为:ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER

这就是它们的差异了,在执行:

$my = new Person();
$name = $my->getName();


调用getName的时候,getName()的作用域(scope)已经被设置成$name对象中,语法分析的时候对于getName中$this->getAge()这样的调用时只是在当前作用域(scope)中调用getAge()函数,不会理会$this的具体值,而在$b->getAge()这样的调用时,会关心$b所对应的值。

0 0
原创粉丝点击