如果您发现 refcount 的解释令人困惑,Xdebug 扩展提供了一个类似于此函数的功能,但由于变量名作为字符串传递,因此 xdebug_debug_zval() 不会使用它自己对 zval 的引用来涂抹 refcount。
(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)
debug_zval_dump — 将内部 zval 结构的字符串表示形式转储到输出
将内部 zval(Zend 值)结构的字符串表示形式转储到输出。这主要用于理解或调试 Zend 引擎或 PHP 扩展的实现细节。
value
要转储的变量或值。
values
要转储的其他变量或值。
不返回值。
示例 #1 debug_zval_dump() 示例
<?php
$var1 = 'Hello';
$var1 .= ' World';
$var2 = $var1;
debug_zval_dump($var1);
?>
以上示例将输出
string(11) "Hello World" refcount(3)
注意:理解
refcount
如果没有深入了解引擎的实现,此函数显示的
refcount
值可能会令人费解。Zend 引擎出于两种不同的目的使用引用计数
- 使用称为“写时复制”的技术优化内存使用,其中多个持有相同值的变量指向内存中的同一副本。当任何变量被修改时,它将指向内存中的新副本,并且原始副本的引用计数将减少 1。
- 跟踪已通过引用赋值或传递的变量(请参阅 引用详解)。此引用计数存储在单独的引用 zval 上,指向当前值的 zval。此附加 zval 当前不会由 debug_zval_dump() 显示。
因为 debug_zval_dump() 将其输入作为普通参数(按值传递)接收,所以将使用写时复制技术传递它们:而不是复制数据,引用计数将在函数调用期间增加 1。如果函数在接收到参数后修改了它,则将创建副本;由于它没有修改,因此它将显示比调用范围高 1 的引用计数。
参数传递还阻止 debug_zval_dump() 显示已通过引用赋值的变量。为了说明这一点,请考虑上面示例的稍微修改后的版本
<?php
$var1 = 'Hello';
$var1 .= ' World';
// 将三个变量作为对同一值的引用
$var2 =& $var1;
$var3 =& $var1;
debug_zval_dump($var1);
?>以上示例将输出
string(11) "Hello World" refcount(2)尽管 $var1、$var2 和 $var3 链接为引用,但只有值传递给 debug_zval_dump()。该值由引用集使用一次,并在 debug_zval_dump() 内部使用一次,因此显示引用计数为 2。
由于引擎对不同数据类型进行了优化,因此会出现进一步的复杂情况。某些类型(如整数)不使用“写时复制”,因此根本不显示引用计数。在其他情况下,引用计数显示引擎内部使用的额外副本,例如当文字字符串或数组存储为代码指令的一部分时。
如果您发现 refcount 的解释令人困惑,Xdebug 扩展提供了一个类似于此函数的功能,但由于变量名作为字符串传递,因此 xdebug_debug_zval() 不会使用它自己对 zval 的引用来涂抹 refcount。