数组键中的PHP引用

时间:2014-09-29 11:35:13

标签: php arrays reference key

PHP:

$a = array("key" => 23);
var_dump($a);

$c = &$a["key"];
var_dump($a);

unset($c);
var_dump($a);

输出:

array(1) {
  ["key"]=>
  int(23)
}
array(1) {
  ["key"]=>
  &int(23)
}
array(1) {
  ["key"]=>
  int(23)
}

在第二个转储中,“key”的值显示为参考。这是为什么? 如果我使用普通变量而不是数组键执行相同操作,则不会发生这种情况。

我唯一的解释是数组键通常存储为引用,只要符号表中只有一个条目,它就会在转储中显示为标量。

1 个答案:

答案 0 :(得分:1)

在内部,PHP数组是散列图(或字典,或HashTables或任何你想要调用它的东西)。即使是数字索引的数组也可以像哈希表一样实现zval,就像其他任何一样。 但是,您所看到的是预期的行为,解释为both herehere

基本上,你的数组内部是什么样的:

typedef struct _zval_struct {
    zvalue_value value;
    zend_uint refcount__gc;
    zend_uchar type;
    zend_uchar is_ref__gc;
} zval;
//zval_value:
typedef union _zvalue_value {
    long lval;
    double dval;
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;
    zend_object_value obj;
} zvalue_value;

如果是数组,zval.type将被设置为表示zval值是一个数组,因此将使用zval_value.ht成员。
撰写$c = &$a['key']时会发生什么情况:分配给zval的{​​{1}}将会更新:$a['key']将会增加,zval.refcount__gc将设置为1.仅仅因为未复制,但该值由多于1个变量使用:意味着此值引用。 is_ref__gc后,unset($c);会递减,参考会丢失,因此refcount设置为is_ref

现在换一个大问题:当你使用常规的标量变量时,为什么不看同样的事情?好吧,那是因为一个数组是一个HashTable,它有自己的内部引用计数(0)。一旦数组本身为空,它也应该被销毁。通过创建对数组值的引用,并取消设置数组,zval_ptr_dtor应该是GC。但这意味着你可以参考被淹没的zval。{ 因此,数组中的zval也会更改为引用:可以安全地删除引用。所以,如果你这样做:

zval

您的代码仍将按预期运行:$foo = array(123); $bar = &$foo[0]; unset($foo[0]); echo $bar, PHP_EOL; 不再存在,但$foo[0]现在是123的唯一现有引用。

这只是一个非常,真实,简短和不完整的解释,但谷歌PHP内部,内存管理如何工作,如何在内部处理引用,以及垃圾收集器如何使用$bar和{ {1}}成员管理记忆 特别注意内部机制,如copy-on-write和(当查看我在这里提供的第一个链接时),查找看起来像这样的代码片段:

is_ref

因为它涉及引用和数组方面的一些奇怪之处。