为什么从类中设置var会产生不一致的结果

时间:2015-03-21 19:16:32

标签: php class set unset magic-methods

前几天我花了一段时间来调试一个问题,并从unset()类变量和magic __set()方法中发现了奇怪的行为。

所以这就是事情:

class A {
    public $var;

    public function unsetVar() {unset($this->var);}
}

class B extends A {
    public $attr = array();
    public function __set($key, $value) {$this->attr[$key] = $value;}
}

$a = new A();
$a->unsetVar();
$a->var = 'teste';

$b1 = new B();
$b1->var = 'teste';

$b2 = new B();
$b2->unsetVar();
$b2->var = 'teste';

var_dump($a, $b1, $b2);

php在线示例:http://goo.gl/CO3Uxj

var_dump()返回:

object(A)#1 (1) {
  ["var"]=>
  string(5) "teste"
}
object(B)#2 (1) {
  ["attr"]=>
  array(1) {
    ["var"]=>
    string(5) "teste"
  }
}

因此,如果取消设置$ a-> var,那么重置将按预期工作,只是为了确保$ b1-> var将设置var并且不触发魔术方法,但是当在b2时我们取消设置var,然后将触发魔术方法而不重置$ b2-> var。

首先,我认为内部PHP会使用魔术方法__set()来设置通过使用反射或某些内部方法来检查属性存在而未设置的变量。

因为我已经覆盖__set()它会执行我的,但是没有找到任何支持它的东西。

那么,有谁知道它为什么会这样? (有一些文档要支持)

谢谢大家!

1 个答案:

答案 0 :(得分:1)

unset($var)会破坏变量$var,使其无法访问,如果您再次尝试使用$var,则会产生“未定义变量”通知。澄清unset()会破坏variable,而不是value。并且销毁变量意味着它将不再存在(可访问)。

我找不到明确说明这一点的文档,但以下测试支持我的声明(与__set的测试一样)。

我做了以下操作,证明__unset()实际上使变量无法访问:

class x {
    public $var;
}
$x = new x();
  echo '<pre>';
print_r(get_object_vars($x)); //prints Array([var] =>)
      echo '<br>';
unset($x->var); //prints Array()
print_r(get_object_vars($x));

所以,get_object_vars docs声明:

  

根据范围获取给定对象的可访问非静态属性。

__set,文档状态:

  将数据写入不可访问的属性时运行

unset(),文档状态:

  

销毁指定的变量

我从中得出结论'destroys'='使变量无法访问',因为如果unset除了使其无法访问之外还做了其他任何事情,那么[var] =>(或[var] =>NULL)就会打印出来第二次。

回答你的问题。

  

那么,有谁知道它为什么会这样? (有一些文档要支持)

因为它应该。文档并没有明确说明它如何在类变量上起作用。

另外(需要文档),类变量是对值的引用,取消设置引用只会破坏引用而不是值(除非它是对值的唯一引用)。

修改:如果您对此答案不满意,可能会report a documentation bug