PHP源码分析之变量的存储过程分解


Posted in PHP onJuly 03, 2014

PHP代码如下:

$php_var = 1; 

对应C的代码是:

zval* c_var;    //定义PHP变量指针  

MAKE_STD_ZVAL(c_var);  //初始化PHP变量  

ZVAL_LONG(c_var,1) ;//赋值  

ZEND_SET_SYMBL( EG(active_symbol_table), " php_var ", c_var);//注册到全局变量符号表

一.首先看第一行: zval* c_var;//申明一个zval指针c_var; zval的结构如下:

struct _zval_struct {  

    /* Variable information */  

    zvalue_value value;     /* 变量的值 */  

    zend_uint refcount;     /* 引用计数,垃圾回收的时候用到 */  

    zend_uchar type;        /* 变量类型 */  

    zend_uchar is_ref;      /* 是否为引用变量 */  

};  

typedef struct _zval_struct zval; 

其中值zvalue_value的结构如下:

typedef union _zvalue_value {  

    long lval;              /* 长整形*/  

    double dval;            /* 双精度类型 */  

    struct {                  /* 字符串类型的值 */  

        char *val;              

        int len;  

    } str;  

    HashTable *ht;              /* 数组类型的值 */  

    zend_object_value obj;     /*对象类型的值*/  

} zvalue_value; 

二.接下来看第二行: MAKE_STD_ZVAL(new_val);//变量初始化 相关宏如下: //初始化

#define MAKE_STD_ZVAL(zv)                \  

    ALLOC_ZVAL(zv); \  

    INIT_PZVAL(zv);  

  

#define ALLOC_ZVAL(z)   \  

    ZEND_FAST_ALLOC(z, zval, ZVAL_CACHE_LIST)  

  

#define ZEND_FAST_ALLOC(p, type, fc_type)   \  

    (p) = (type *) emalloc(sizeof(type))  

  

#define INIT_PZVAL(z)       \  

    (z)->refcount = 1;      \  

    (z)->is_ref = 0; 

展开后为:

(c_var) = (zval *) emalloc(sizeof(zval));  //分配内存  

(c_var)-> refcount = 1;  //引用计数初始化  

(c_var)-> is_ref = 0; //是否引用 

可以看到其作用就是分配内存,初始化refcount,is_ref

三.下面看第三行 ZVAL_LONG(c_var,1) 相关宏为:

//定义值  

#define ZVAL_LONG(z, l) {           \  

     Z_TYPE_P(z) = IS_LONG;      \  

     Z_LVAL_P(z) = l;            \  

}  

#define Z_TYPE_P(zval_p)    Z_TYPE(*zval_p)  

#define Z_TYPE(zval)        (zval).type  

#define Z_LVAL_P(zval_p)    Z_LVAL(*zval_p)  

#define Z_LVAL(zval)            (zval).value.lval 

展开后为:

(* c_var).type = IS_LONG;  

(* c_var).value = 1; 

四:接下来看第四行: ZEND_SET_SYMBOL( EG(active_symbol_table), “php_var”, c_var); 首先说明下PHP的变量是存在一个hashtable里的

struct _zend_executor_globals {    

        ….  

        HashTable symbol_table;//全局变量的符号表    

        HashTable *active_symbol_table;//局部变量的符号表    

        …..  

    };   

Hashtable的Key为变量的名称,即php_var,值为指向PHP变量的指针,即c_var指针; 相关宏为:

#define ZEND_SET_SYMBOL(symtable, name, var)          \   {                                                     \  

        char *_name = (name);                         \  

        ZEND_SET_SYMBOL_WITH_LENGTH(symtable, _name, strlen(_name)+1, var, 1, 0);   \  

}  

//主要的实现为下面这个函数:  

#define ZEND_SET_SYMBOL_WITH_LENGTH(symtable, name, name_length, var, _refcount, _is_ref)                                                       \  

    {                                                                         

        zval **orig_var;                                        \   

        if (zend_hash_find(symtable, (name), (name_length), (void **) &orig_var)==SUCCESS                                                         \  

            && PZVAL_IS_REF(*orig_var)) {                     \  

            (var)->refcount = (*orig_var)->refcount;                  \  

            (var)->is_ref = 1;                                \  

            if (_refcount) {                                      \  

                (var)->refcount += _refcount-1;               \  

            }                                             \  

            zval_dtor(*orig_var);                             \  

            **orig_var = *(var);                                  \  

            FREE_ZVAL(var);                               \  

        } else {                                              \  

            (var)->is_ref = _is_ref;                              \  

            if (_refcount) {                                      \  

                (var)->refcount = _refcount;                      \  

            }                                             \  

            zend_hash_update(symtable, (name), (name_length), &(var), sizeof(zval *), NULL);                                                           \  

        }                                                  \  

    }            

该函数的功能是:
1. 如果全局符号表已经存在该变量且是引用类型,则

a. 将原来变量的引用计数refcount,is_ref信息赋给c_var;
b. 释放掉原来变量zvalue的值,比如原来其值指向的是一个mysql连接资源,则释放该资源。
c. 将c_var指向的变量赋值给原来的变量 d. 释放c_var的内存空间 这样保证了,如果变量被应用,值一起改变。比如如果前面有$b=&a;

2. 如果全局符号表不存在该变量或者存在该变量但不是引用变量,则直接改变其值。

PHP 相关文章推荐
为php4加入动态flash文件的生成的支持
Oct 09 PHP
用Php实现链结人气统计
Oct 09 PHP
php中对xml读取的相关函数的介绍一
Jun 05 PHP
PHP写入WRITE编码为UTF8的文件的实现代码
Jul 07 PHP
JS 网站性能优化笔记
May 24 PHP
PHP抓取、分析国内视频网站的视频信息工具类
Apr 02 PHP
ThinkPHP连接数据库及主从数据库的设置教程
Aug 22 PHP
ThinkPHP添加更新标签的方法
Dec 05 PHP
php支持中文字符串分割的函数
May 28 PHP
Yii2中cookie用法示例分析
Jul 18 PHP
php微信公众号开发(4)php实现自定义关键字回复
Dec 15 PHP
关于laravel 数据库迁移中integer类型是无法指定长度的问题
Oct 09 PHP
ThinkPHP让分页保持搜索状态的方法
Jul 02 #PHP
ThinkPHP实现批量删除数据的代码实例
Jul 02 #PHP
Thinkphp中import的几个用法详细介绍
Jul 02 #PHP
改写ThinkPHP的U方法使其路由下分页正常
Jul 02 #PHP
PHP反射使用实例和PHP反射API的中文说明
Jul 02 #PHP
用PHP解决的一个栈的面试题
Jul 02 #PHP
函数中使用require_once问题深入探讨 优雅的配置文件定义方法推荐
Jul 02 #PHP
You might like
跟我学小偷程序之成功偷取首页(第三天)
2006/10/09 PHP
PHP删除特定数组内容并且重建数组索引的方法.
2011/03/25 PHP
php时区转换转换函数
2014/01/07 PHP
php模拟post提交数据的方法
2015/02/12 PHP
PHP+apc+ajax实现的ajax_upload上传进度条代码
2016/01/25 PHP
php通过PHPExcel导入Excel表格到MySQL数据库的简单实例
2016/10/29 PHP
PHP+MariaDB数据库操作基本技巧备忘总结
2018/05/21 PHP
flash javascript之间的通讯方法小结
2008/12/20 Javascript
jQuery无刷新切换主题皮肤实例讲解
2015/10/21 Javascript
限制复选框最多选择项的实现代码
2016/05/30 Javascript
js提示框替代系统alert,自动关闭alert对话框的实现方法
2016/11/07 Javascript
JS中如何实现Laravel的route函数详解
2017/02/12 Javascript
JavaScript正则表达式函数总结(常用)
2018/02/22 Javascript
vue-router 源码之实现一个简单的 vue-router
2018/07/02 Javascript
微信小程序的开发范式BeautyWe.js入门详解
2019/07/10 Javascript
React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析
2020/01/06 Javascript
vue3.0 自适应不同分辨率电脑的操作
2021/02/06 Vue.js
简单实现python爬虫功能
2015/12/31 Python
Python中模块pymysql查询结果后如何获取字段列表
2017/06/05 Python
Python实现将文本生成二维码的方法示例
2017/07/18 Python
浅谈python for循环的巧妙运用(迭代、列表生成式)
2017/09/26 Python
Anaconda2下实现Python2.7和Python3.5的共存方法
2018/06/11 Python
django项目中使用手机号登录的实例代码
2019/08/15 Python
Html5基于canvas实现电子签名并生成PDF文档
2020/12/07 HTML / CSS
Lancome兰蔻官方旗舰店:来自法国的世界知名美妆品牌
2018/06/14 全球购物
卡骆驰英国官网:Crocs英国
2019/08/22 全球购物
常用UNIX 命令(Linux的常用命令)
2015/12/26 面试题
工厂仓管员岗位职责
2014/01/01 职场文书
致接力运动员广播稿
2014/02/17 职场文书
《阳光》教学反思
2014/02/23 职场文书
班委竞选演讲稿
2014/04/28 职场文书
社会工作专业求职信
2014/07/15 职场文书
先进班集体申报材料
2014/12/26 职场文书
工作感言一句话
2015/08/01 职场文书
银行求职信范文
2019/05/13 职场文书
NodeJs内存占用过高的排查实战记录
2021/05/10 NodeJs