用'new'实例化时到底发生了什么?

时间:2011-12-29 13:49:54

标签: php reference new-operator php-internals

让我们考虑以下代码:

class a {
    public $var1;
    function disp(){
        echo $this->var1;
        }    
    }

$obj1 = new a;
echo '<br/>After instantiation into $obj1:<br/>';    
xdebug_debug_zval('obj1');  

$obj1->var1 = "Hello ";
echo '<br/><br/>After assigning "Hello" to  $obj->var1:<br/>';
$obj1->disp();

echo "<br/><br/>";  
xdebug_debug_zval('obj1');  

输出:

  

实例化为$ obj1后:
  obj1:(refcount = 1,is_ref = 0)= class a {public $ var1 =(refcount = 2,is_ref = 0)= NULL}

     

将“Hello”分配给$ obj-&gt; var1:
  你好

     

obj1:(refcount = 1,is_ref = 0)= class a {public $ var1 =(refcount = 1,is_ref = 0)='Hello'}

一个接一个:

  

实例化为$ obj1后:
  obj1:(refcount = 1,is_ref = 0)= class a {public $ var1 =(refcount = 2,is_ref = 0)= NULL}

为什么$obj1->var1只有一个a类对象时才有refcount=2

这是因为new运算符如何进行分配? PHP使用引用进行赋值。使用new实例化时,没有符号/变量名与该实例关联。但是,类属性确实有名称。是recount=2因为这个吗?

如果是这种情况,则发生C.O.W(写入时复制),并使用浅拷贝WRT类实例。虽然属性仍指向使用new在实例化期间创建的zval属性。

现在,

  

将“Hello”分配给$ obj-&gt; var1:
  你好

     

obj1:(refcount = 1,is_ref = 0)= class a {public $ var1 =(refcount = 1,is_ref = 0)='Hello'}

那么,当我为属性$obj1->var1赋值时,为该属性分配一个新的zval容器,从而refcount=1

这是否意味着使用new在实例化期间创建的zval容器仍然存在但由于没有与之关联的符号/变量名称而无法访问?

请注意(来自xdebug: Variable Display Features):
debug_zval_dump()xdebug_debug_zval()不同。

  

void xdebug_debug_zval( [string varname [,...]]

     

显示有关变量的信息

     

此函数显示有关一个或多个变量的结构化信息,包括其类型,值和引用计数信息。使用值递归地探索数组。此函数的实现与PHP的debug_zval_dump()函数不同,以解决该函数所具有的问题,因为变量本身实际上已传递给函数。 Xdebug的版本更好,因为它使用变量名来查找内部符号表中的变量并直接访问所有属性,而无需处理实际将变量传递给函数。结果是该函数返回的信息比PHP自己显示zval信息的函数准确得多。

UPDATE Dec 31th 2011:

  

我正在尝试查看使用 new 时内存分配的方式。但是我现在还有太多其他的事要做。我希望我能尽快发布有用的更新。   在此之前,这里是我正在查看的代码链接:

     

2 个答案:

答案 0 :(得分:4)

添加另一个实例化$obj2 = new a;会将引用计数增加到3而不是4,所以这是因为调用xdebug_debug_zval而发生的事情。 xdebug函数的目的是避免将变量传递给函数和(可能)创建额外引用时的混淆。

不幸的是,这不适用于成员变量;为这些zval创建另一个引用以便导出它们。因此,debug_zval_dump documentation注释中列出的所有警告和令人困惑的情况仍然适用于成员变量。

答案 1 :(得分:2)

我认为下一页的“注意:注意引用计数”一节解释了这一点: http://php.net/manual/en/function.debug-zval-dump.php

它表明如果zend优化了它的传递方式,则引用计数会增加,但是当调用copy-on-write时会出现“警告”,将refcount返回到1。

希望有所帮助