我的编程空间,编程开发者的网络收藏夹
学习永远不晚

变量改变时PHP内核做了哪些工作

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

变量改变时PHP内核做了哪些工作

本篇内容主要讲解“变量改变时PHP内核做了哪些工作”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“变量改变时PHP内核做了哪些工作”吧!

看下面的内容之前先对zval这个结构体做个了解

typedef struct _zval_struct {     zvalue_value value;     zend_uint refcount;     zend_uchar type;     zend_uchar is_ref; } zval;

zval结构体中共有4个元素,value是一个联合体,用来真正的存储zval的值,refcount用来计数该zval被多少个变量使用,type表示zval所存储的数据类型,is_ref用来标志该zval是否被引用。

引用计数

<php     $a = 'Hello World';     $b = $a;     unset($a); >

我们一起来剖析下上面这段代码:

  • $a = 'Hello World';首先这句代码被执行,内核创建一个变量,并分配12字节的内存去存储字符串'Hello World'和末尾的NULL。

  • $b = $a;接着执行这句代码,执行这句的时候内核里面发生了什么呢?

    • $a所指向的zval中的refcount进行加1操作。

    • 将变量$b指向$a所指向的zval。
      在内核中大概是这样的,其中active_symbol_table是当前的变量符号表


    1.     zval *helloval; 

    2.     MAKE_STD_ZVAL(helloval); 

    3.     ZVAL_STRING(helloval, "Hello World", 1); 

    4.     zend_hash_add(EG(active_symbol_table), "a", sizeof("a"), 

    5.                                         &helloval, sizeof(zval*), NULL); 

    6.     ZVAL_ADDREF(helloval); 

    7.     zend_hash_add(EG(active_symbol_table), "b", sizeof("b"), 

    8.                                         &helloval, sizeof(zval*), NULL); 

  • unset($a);这句代码执行后,内核会将a对应的zval结构体中的refcount计数减一,b还和原来一样

写时复制

<?php     $a = 1;     $b = $a;     $b += 5; ?>

上面这段代码执行完之后,一般肯定希望$a=1,$b=6,但是如果像引用计数那样,$a$b指向相同的zval,修改$b之后$a不是也变了?
这个具体是怎么实现的呢,我们一起来看下:

  • $a = 1;内核创建一个zval,并分配4个字节存储数字1。

  • $b = $a;这一步和引用计数中的第二步一样,将$b指向和$a相同的zval,并将zval中的引用计数值refcount加1。

  • $b += 5;关键是这一步,这一步骤发生了什么呢,怎么确保修改之后不影响$a

    • 其实Zend内核在改变zval之前都会去进行get_var_and_separete操作,如果recfount>1,就需要分离就创建新的zval返回,否则直接返回变量所指向的zval,下面看看如何分离产生新的zval。

    • 复制一个和$b所指向zval一样的zval。

    • $b所指向的zval中的refcount计数减1。

    • 初始化生成的新zval,设置refcount=1,is_ref=0。

    • $b指向新生成的zval。

    • 对新生成的zval进行操作,这就是写时复制。
      下面看看内核中分离时的主要代码:


    1. zval *get_var_and_separate(char *varname, int varname_len TSRMLS_DC) 

    2.     zval **varval, *varcopy; 

    3.     if (zend_hash_find(EG(active_symbol_table), 

    4.                     varname, varname_len + 1, (void**)&varval) == FAILURE) { 

    5.      

    6.     return NULL; 

    7. if ((*varval)->is_ref || (*varval)->refcount < 2) { 

    8.      

    9.     return *varval; 

    10.  

    11. MAKE_STD_ZVAL(varcopy); 

    12. varcopy = *varval; 

    13.  

    14. zval_copy_ctor(varcopy); 

    15.  

    16.  

    17. zend_hash_del(EG(active_symbol_table), varname, varname_len + 1); 

    18.  

    19.  

    20. varcopy->refcount = 1; 

    21. varcopy->is_ref = 0; 

    22. zend_hash_add(EG(active_symbol_table), varname, varname_len + 1, 

    23.                                         &varcopy, sizeof(zval*), NULL); 

    24.  

    25. return varcopy; 

写时改变

<?php     $a = 1;     $b = &$a;     $b += 5; ?>

上面这段代码执行完之后一般希望是:$a == $b == 1。这个又是怎么实现的呢?

  • $a = 1;这一步骤和写时复制中的***步一样。

  • $b = &$a;这一步骤内核会将$b指向$a所指向的zval,将zval中的refcount加1,并将zval中的is_ref置为1。

  • $b += 5;这一步骤和写时复制中的第三步骤一样,但是内核中发生的事情却不一样。

    • 内核看到$b进行变化的时候,也会执行get_var_and_separate函数,看是否需要分离。

    • 如果(*varval)->is_ref的话也会直接返回$b所指向的zval,不去分离产生新的zval,不管zval的refcount是否>1。

    • 这时候再去修改$b值,$a的值也就改变了,因为他们指向相同的zval。

分离的问题

说道现在聪明的你可能已经看出点问题了,如果一个zval结构体既有refcount计数又有is_ref引用这个时候怎么办?

<?php     $a = 1;     $b = $a;     $c = &$a; ?>

如果出现上面这种情况的时候,如果$a、$b、$c指向同一个zval结构体,进行改变的时候Zend到底去听谁的?其实这个地方不会指向同一个zval了。
如果对一个is_ref = 0 && refcount >1的zval进行写时改变这种赋值形式(就是引用赋值)的时候,Zend会将等号右边的变量分离出来一个新的zval,
对这个zval进行初始化,对之前的zval的refcount进行减1操作,让等号左边的变量指向这个新的zval,refcount进行加1操作,is_ref=1。看看下面这张图片

变量改变时PHP内核做了哪些工作

<?php     $a = 1;     $b = &$a;     $c = $a; ?>

上面这又是另外一种情况,在is_ref = 1的情况下,试图单纯的进行refcount+1操作的时候会分离出来一个新的zval给等号左边的变量,并初始化他,看看下面这张图片

变量改变时PHP内核做了哪些工作

到此,相信大家对“变量改变时PHP内核做了哪些工作”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

变量改变时PHP内核做了哪些工作

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

变量改变时PHP内核做了哪些工作

本篇内容主要讲解“变量改变时PHP内核做了哪些工作”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“变量改变时PHP内核做了哪些工作”吧!看下面的内容之前先对zval这个结构体做个了解typedef
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录