让我们考虑以下代码:
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->var1
有refcount=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函数的目的是避免将变量传递给函数和(可能)创建额外的引用所造成的混淆。
我认为下面页面上的"注意:注意重新计数"一节解释了这一点:http://php.net/manual/en/function.debug-zval-dump.php
它表明,如果zend优化了它的传递方式,则refcount会增加,但是"警告"是当调用写时复制时,将refcount返回到1。
希望有帮助