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.MVC的模板标签系统(四)
Sep 05 PHP
php中定义网站根目录的常用方法
Aug 08 PHP
php实现分页工具类分享
Jan 09 PHP
ThinkPHP无限级分类原理实现留言与回复功能实例
Oct 31 PHP
推荐5款跨平台的PHP编辑器
Dec 25 PHP
php的sso单点登录实现方法
Jan 08 PHP
Smarty最简单实现列表奇偶变色的方法
Jul 01 PHP
如何使用GDB调试PHP程序
Dec 08 PHP
PHP上传图片、删除图片简单实例
Nov 12 PHP
Centos 6.5下PHP 5.3安装ffmpeg扩展的步骤详解
Mar 02 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
Mar 09 PHP
PHP实现考试倒计时功能代码
Apr 16 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
Laravel中如何增加自定义全局函数详解
2017/05/09 PHP
28个JS验证函数收集
2010/03/02 Javascript
JS中Iframe之间传值及子页面与父页面应用
2013/03/11 Javascript
Jquery动态添加及删除页面节点元素示例代码
2014/06/16 Javascript
js简单实现点击左右运动的方法
2015/04/10 Javascript
详解js中构造流程图的核心技术JsPlumb(2)
2015/12/08 Javascript
老生常谈遮罩层 滚动条的问题
2016/04/29 Javascript
jQuery对象的链式操作用法分析
2016/05/10 Javascript
浅谈JavaScript中数组的增删改查
2016/06/20 Javascript
详解Angular中$cacheFactory缓存的使用
2016/08/19 Javascript
nodejs爬虫初试superagent和cheerio
2018/03/05 NodeJs
关于单文件组件.vue的使用
2018/09/20 Javascript
JS实现深度优先搜索求解两点间最短路径
2019/01/17 Javascript
NodeJs 实现简单WebSocket即时通讯的示例代码
2019/08/05 NodeJs
微信公众号生成新浪短网址的实现(快速生成)
2019/08/18 Javascript
Vue登录主页动态背景短视频制作
2019/09/21 Javascript
Vue中ref和$refs的介绍以及使用方法示例
2021/01/11 Vue.js
[02:43]中国五虎出征TI3视频
2013/08/02 DOTA
[03:07]2015国际邀请赛选手档案EHOME.rOtK 是什么让他落泪?
2015/07/31 DOTA
Python中的一些陷阱与技巧小结
2015/07/10 Python
pandas 条件搜索返回列表的方法
2018/10/30 Python
Python3.5内置模块之shelve模块、xml模块、configparser模块、hashlib、hmac模块用法分析
2019/04/27 Python
Python with用法:自动关闭文件进程
2019/07/10 Python
使用python-opencv读取视频,计算视频总帧数及FPS的实现
2019/12/10 Python
详解Django3中直接添加Websockets方式
2020/02/12 Python
基于Python和C++实现删除链表的节点
2020/07/06 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
2020/08/03 Python
实习销售业务员自我鉴定
2013/09/21 职场文书
工厂门卫岗位职责
2013/11/25 职场文书
学生请假条格式
2014/04/11 职场文书
夏洛特的网观后感
2015/06/15 职场文书
2015小学教育教学工作总结
2015/07/21 职场文书
初中体育教学随笔
2015/08/15 职场文书
商业计划书格式、范文
2019/03/21 职场文书
Python数据分析入门之数据读取与存储
2021/05/13 Python
戴尔Win11系统no bootable devices found解决教程
2022/09/23 数码科技