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 相关文章推荐
简单易用的计数器(数据库)
Oct 09 PHP
超级实用的7个PHP代码片段分享
Jan 05 PHP
解析phpstorm + xdebug 远程断点调试
Jun 20 PHP
九个你必须知道而且又很好用的php函数和特点
Aug 08 PHP
PHP计算2点经纬度之间的距离代码
Aug 12 PHP
PHP实现多文件上传的方法
Jul 08 PHP
PHP创建多级目录的两种方法
Oct 28 PHP
超强多功能php绿色集成环境详解
Jan 25 PHP
PHP实现求连续子数组最大和问题2种解决方法
Dec 26 PHP
Laravel框架基于中间件实现禁止未登录用户访问页面功能示例
Jan 17 PHP
PHP rmdir()函数的用法总结
Jul 02 PHP
Laravel框架控制器,视图及模型操作图文详解
Dec 04 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 无限分类三种方式 非函数的递归调用!
2011/08/26 PHP
php中使用__autoload()自动加载未定义类的实现代码
2013/02/06 PHP
PHP获取MAC地址的具体实例
2013/12/13 PHP
PHP递归删除目录几个代码实例
2014/04/21 PHP
探寻PHP脚本不报错的原因
2014/06/12 PHP
Javascript弹出窗口的各种方法总结
2013/11/11 Javascript
js获取上传文件大小示例代码
2014/04/10 Javascript
js控制文本框输入的字符类型方法汇总
2015/06/19 Javascript
jQuery实现的文字hover颜色渐变效果实例
2016/02/20 Javascript
jQuery自制提示框tooltip改进版
2016/08/01 Javascript
easyui datebox 时间限制,datebox开始时间限制结束时间,datebox截止日期比起始日期大的实现代码
2017/01/12 Javascript
JS二分查找算法详解
2017/11/01 Javascript
vue实现全匹配搜索列表内容
2019/09/26 Javascript
JavaScript动画实例之粒子文本的实现方法详解
2020/07/28 Javascript
python中global用法实例分析
2015/04/30 Python
详解Python迭代和迭代器
2016/03/28 Python
python监控文件或目录变化
2016/06/07 Python
Python中PyQt5/PySide2的按钮控件使用实例
2019/08/17 Python
python遍历文件目录、批量处理同类文件
2019/08/31 Python
Python 用turtle实现用正方形画圆的例子
2019/11/21 Python
pytorch之添加BN的实现
2020/01/06 Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
2020/01/10 Python
利用Tensorflow的队列多线程读取数据方式
2020/02/05 Python
Tensorflow 多线程设置方式
2020/02/06 Python
python标准库sys和OS的函数使用方法与实例详解
2020/02/12 Python
Python基于unittest实现测试用例执行
2020/11/25 Python
大韩航空官方网站:Korean Air
2017/10/25 全球购物
高性能装备提升营地:Kammok
2019/02/27 全球购物
橄榄树药房:OLIVEDA
2019/09/01 全球购物
PHP如何调用MYSQL存储过程
2014/05/30 面试题
高级Java程序员面试题
2016/06/23 面试题
超市营业员求职简历的自我评价
2013/10/17 职场文书
公司股东出资证明书
2014/11/01 职场文书
储备店长岗位职责
2015/04/14 职场文书
利用Python网络爬虫爬取各大音乐评论的代码
2021/04/13 Python
MySQL8.0的WITH查询详情
2021/08/30 MySQL