设为首页 收藏本站
查看: 925|回复: 0

[经验分享] php数组复制的实现

[复制链接]

尚未签到

发表于 2018-12-19 06:27:02 | 显示全部楼层 |阅读模式
  在php内部复制数组我们经常会这么写:
  zval *conf = NULL;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &conf) == FAILURE) {
  return;
  }
  zval tmp;
  tmp = *conf;
  zval_copy_ctor(&tmp);
  这段逻辑很简单,接受一个用户传进来的数组参数,然后将其复制一份给tmp这个变量。
  我们注意这句:tmp = *conf;  这其实就是c语言的结构体变量赋值和下面这段是一样的意思:
  struct  xinhua
  {
  int   a;
  int   b;
  }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指针。
DSC0000.jpg

  我们看到ht指针的值是相同的,这验证了我们上面的说法,但是这显然有悖于我们数组复制的目的,现在该zval_copy_ctor出场了!
  zval_copy_ctor最终会调用_zval_copy_ctor_func这个zend API我们直接看他的源码:
  case IS_ARRAY:
  case IS_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查看下:
DSC0001.jpg

  此时这tmp和conf这两个zval所引用的hashtable已经不是一个了。
  我们再注意下zend_hash_copy函数的(copy_ctor_func_t) zval_add_ref这块,其实zend_hash_copy的内部实现就是遍历hashtable,然后给每个元素都执行我们传进来的zval_add_ref这个函数。
  也就是说真正数组的元素并没有复制,而是添加引用计数这样的方式来避免性能损耗。
  over ~


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-652969-1-1.html 上篇帖子: php-cp介绍 下篇帖子: php的基础总结
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表