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 相关文章推荐
用PHP来写记数器(详细介绍)
Oct 09 PHP
PHP获取表单textarea数据中的换行问题
Sep 10 PHP
关于php内存不够用的快速解决方法
Oct 26 PHP
PHP中把stdClass Object转array的几个方法
May 08 PHP
php json_encode()函数返回json数据实例代码
Oct 10 PHP
Codeigniter发送邮件的方法
Mar 19 PHP
php计算给定时间之前的函数用法实例
Apr 03 PHP
PHP常见数组函数用法小结
Mar 21 PHP
thinkphp多表查询两表有重复相同字段的完美解决方法
Sep 22 PHP
Laravel框架基于中间件实现禁止未登录用户访问页面功能示例
Jan 17 PHP
PHP上传图片到数据库并显示的实例代码
Dec 20 PHP
PHP 实现base64编码文件上传出现问题详解
Sep 01 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
PHP下对字符串的递增运算代码
2010/08/21 PHP
php无限极分类递归排序实现方法
2014/11/11 PHP
php实现的日历程序
2015/06/18 PHP
php策略模式简单示例分析【区别于工厂模式】
2019/09/25 PHP
用javascript父窗口控制只弹出一个子窗口
2007/04/10 Javascript
jQuery的实现原理的模拟代码 -1 核心部分
2010/08/01 Javascript
浅谈 javascript 事件处理
2015/01/04 Javascript
jQuery鼠标悬浮链接弹出跟随图片实例代码
2016/01/08 Javascript
Vue.js中数组变动的检测详解
2016/10/12 Javascript
微信小程序 火车票查询实例讲解
2016/10/17 Javascript
Vue自定义指令介绍(2)
2016/12/08 Javascript
详解微信小程序开发—你期待的分享功能来了,微信小程序序新增5大功能
2016/12/23 Javascript
Node.js 的模块知识汇总
2017/08/16 Javascript
Vue实现web分页组件详解
2017/11/28 Javascript
vue2 设置router-view默认路径的实例
2018/09/20 Javascript
vue使用原生swiper代码实例
2020/02/05 Javascript
[02:24]DOTA2亚洲邀请赛 NAVI战队出场宣传片
2015/02/07 DOTA
[01:10]为家乡而战!完美世界城市挑战赛全国总决赛花絮
2019/07/25 DOTA
python操作ssh实现服务器日志下载的方法
2015/06/03 Python
黑科技 Python脚本帮你找出微信上删除你好友的人
2016/01/07 Python
总结用Pdb库调试Python的方式及常用的命令
2016/08/18 Python
Python 专题一 函数的基础知识
2017/03/16 Python
python 自定义异常和异常捕捉的方法
2018/10/18 Python
Python实现从SQL型数据库读写dataframe型数据的方法【基于pandas】
2019/03/18 Python
使用Python实现牛顿法求极值
2020/02/10 Python
Python爬虫JSON及JSONPath运行原理详解
2020/06/04 Python
Python unittest生成测试报告过程解析
2020/09/08 Python
python爬虫搭配起Bilibili唧唧的流程分析
2020/12/01 Python
详解修改Anaconda中的Jupyter Notebook默认工作路径的三种方式
2021/01/24 Python
印度最大的旅游网站:MakeMyTrip
2016/10/05 全球购物
Stio官网:男女、儿童户外服装
2019/12/13 全球购物
优秀大学生求职自荐信范文
2014/04/19 职场文书
《夕阳真美》教学反思
2014/04/27 职场文书
房屋认购协议书
2015/01/29 职场文书
Java实现房屋出租系统详解
2021/10/05 Java/Android
Java设计模式中的命令模式
2022/04/28 Java/Android