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


What is exactly happening when instantiating with 'new'?

让我们考虑以下代码:

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->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}

当只有一个a类对象时,为什么$obj1->var1refcount=2 ?

是因为new操作符的赋值方式吗?PHP对引用进行赋值。当用new实例化时,没有符号/变量名与该实例相关联。但是,类属性确实有名称。recount=2是因为这个吗?

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

现在

将"Hello"赋值给$obj->var1后:
你好

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

那么,当我给属性$obj1->var1赋值时,为该属性和refcount=1创建一个新的zval容器?

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

请注意(来自xdebug: Variable Display Features):
debug_zval_dump()xdebug_debug_zval()不一样

空白xdebug_debug_zval ( [string varname[…]] )

显示变量的信息。

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

UPDATE : Dec 31th 2011:

我想看看当使用new时内存分配是如何发生的。但是我现在有太多其他的事情要做。我希望我能尽快发布一个有用的更新。在此之前,这里是我正在查看的代码链接:


  • 寄存器指针new = malloc (sizeof (header) + size);

  • expr_without_variable: T_NEW class_name_reference
  • 函数zend_do_fetch_class

添加另一个实例化$obj2 = new a;将refcount增加到3,而不是4,所以这是调用xdebug_debug_zval的结果。xdebug函数的目的是避免将变量传递给函数和(可能)创建额外的引用所造成的混淆。

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

我认为下面页面上的"注意:注意重新计数"一节解释了这一点:http://php.net/manual/en/function.debug-zval-dump.php

它表明,如果zend优化了它的传递方式,则refcount会增加,但是"警告"是当调用写时复制时,将refcount返回到1。

希望有帮助