加入收藏 | 设为首页 | 会员中心 | 我要投稿 威海站长网 (https://www.0631zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php数组复制的实现

发布时间:2022-11-19 16:01:04 所属栏目:PHP教程 来源:转载
导读: 在php内部复制数组我们经常会这么写:
zval*conf=NULL;
if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"a",&conf)==FAILURE){
return;
}
zvaltmp;
tmp=*conf;
zval_copy_ctor(&tmp);

在php内部复制数组我们经常会这么写:

zval*conf=NULL;

if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"a",&conf)==FAILURE){

return;

}

zvaltmp;

tmp=*conf;

zval_copy_ctor(&tmp);

这段逻辑很简单,接受一个用户传进来的数组参数PHP数组,然后将其复制一份给tmp这个变量。

我们注意这句:tmp = *conf; 这其实就是c语言的结构体变量赋值和下面这段是一样的意思:

structxinhua

{

inta;

intb;

}A,B;

A=B;

记得上学的时候谭浩强老人家说这样的结构体变量赋值是不行的,坑!而php手册里面zval复制介绍这块用大量的篇幅描述为“=”号的运算符重载,对于新学者还是会有蒙圈的感觉,会认为这个tmp=*conf;是运算符重载,个人觉得php手册描述的不妥。

赋值完毕后,tmp这个zval结构所有成员的值都和conf一样了包括ht这个指针的值。

btw:我们脑中一定有这样一个概念,那就是php里面所有的变量都是用zval表示,而数组在php内部是通过hashtable来表示的,zval通过ht这个指针指向这个hashtable。

现在我们通过gdb打断点来查看tmp和conf的ht指针。

我们看到ht指针的值是相同的,这验证了我们上面的说法,但是这显然有悖于我们数组复制的目的,现在该zval_copy_ctor出场了!

zval_copy_ctor最终会调用_zval_copy_ctor_func这个zend API我们直接看他的源码:

caseIS_ARRAY:

caseIS_CONSTANT_ARRAY:{

zval*tmp;

HashTable*original_ht=zvalue->value.ht;

HashTable*tmp_ht=NULL;

TSRMLS_FETCH();

if(zvalue->value.ht==&EG(symbol_table)){

return;

}

ALLOC_HASHTABLE_REL(tmp_ht);

zend_hash_init(tmp_ht,zend_hash_num_elements(original_ht),NULL,ZVAL_PTR_DTOR,0);

zend_hash_copy(tmp_ht,original_ht,(copy_ctor_func_t)zval_add_ref,(void*)&tmp,sizeof(zval*));

zvalue->value.ht=tmp_ht;

}

break;

我们看到php通过ALLOC_HASHTABLE_REL(tmp_ht);重新在堆上分配了一个hashtable结构体,同时调用zend_hash_init初始化hash表,紧接着调用zend_hash_copy复制conf的hashtable,最后把复制好的hashtable地址赋值给我们最终的tmp的ht指针。

我们通过gdb查看下:

此时这tmp和conf这两个zval所引用的hashtable已经不是一个了。

我们再注意下zend_hash_copy函数的(copy_ctor_func_t)zval_add_ref这块,其实zend_hash_copy的内部实现就是遍历hashtable,然后给每个元素都执行我们传进来的zval_add_ref这个函数。

也就是说真正数组的元素并没有复制,而是添加引用计数这样的方式来避免性能损耗。

over ~

(编辑:威海站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!