使用“新”实例化时究竟发生了什么?

2022-08-30 23:44:10

让我们考虑以下代码:

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');  

输出:

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

将“Hello”分配给$obj->var1后:
Hello

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

一一:

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

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

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

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

现在

将“Hello”分配给$obj->var1后:
Hello

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

因此,当我为该属性分配一个值时,该属性的新 zval 容器,因此 ?$obj1->var1refcount=1

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

请注意(来自 xdebug:可变显示功能):
与 不同。debug_zval_dump()xdebug_debug_zval()

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

显示有关变量的信息

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

更新Dec 31th 2011:

我正在尝试查看使用内存时内存分配如何发生。但是我现在必须做太多其他事情。我希望我能够很快发布有用的更新。在此之前,以下是我正在查看的代码的链接:


答案 1

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

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


答案 2

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

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

希望有所帮助


推荐