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 相关文章推荐
Get或Post提交值的非法数据处理
Oct 09 PHP
php 动态执行带有参数的类方法
Apr 10 PHP
Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
Jun 14 PHP
php小经验:解析preg_match与preg_match_all 函数
Jun 29 PHP
php将access数据库转换到mysql数据库的方法
Dec 24 PHP
19个Android常用工具类汇总
Dec 30 PHP
php清除和销毁session的方法分析
Mar 19 PHP
php实现对象克隆的方法
Jun 20 PHP
php opendir()列出目录下所有文件的实例代码
Oct 02 PHP
php登录超时检测功能实例详解
Mar 21 PHP
php安全配置记录和常见错误梳理(总结)
Mar 28 PHP
使用Laravel中的查询构造器实现增删改查功能
Sep 03 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简单的留言板与回复功能具体实现
2014/02/19 PHP
在win7中搭建Linux+PHP 开发环境
2014/10/08 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
Smarty简单生成表单元素的方法示例
2016/05/23 PHP
php文件上传 你真的掌握了吗
2016/11/28 PHP
javascript 动态调整图片尺寸实现代码
2009/12/28 Javascript
jQuery学习笔记之jQuery动画效果
2013/09/09 Javascript
快速解决jquery之get缓存问题的最简单方法介绍
2013/12/19 Javascript
jquery操作select详解(取值,设置选中)
2014/02/07 Javascript
Node.js中使用计时器定时执行函数详解
2014/08/15 Javascript
JavaScript中解析JSON数据的三种方法
2015/07/03 Javascript
详解js中构造流程图的核心技术JsPlumb
2015/12/08 Javascript
使用jquery datatable和bootsrap创建表格实例代码
2017/03/17 Javascript
浅谈React Native 中组件的生命周期
2017/09/08 Javascript
JS+canvas动态绘制饼图的方法示例
2017/09/12 Javascript
bootstrap日期插件daterangepicker使用详解
2017/10/19 Javascript
Angular2之二级路由详解
2018/08/31 Javascript
js实现简单分页导航栏效果
2019/06/28 Javascript
[00:35]DOTA2上海特级锦标赛 EG战队宣传片
2016/03/04 DOTA
Python用imghdr模块识别图片格式实例解析
2018/01/11 Python
Python迭代器和生成器定义与用法示例
2018/02/10 Python
Django中反向生成models.py的实例讲解
2018/05/30 Python
Pandas读取并修改excel的示例代码
2019/02/17 Python
python调用matlab的m自定义函数方法
2019/02/18 Python
Python开发网站目录扫描器的实现
2019/02/21 Python
python文档字符串(函数使用说明)使用详解
2019/07/30 Python
Python类中的魔法方法之 __slots__原理解析
2019/08/26 Python
Python爬虫小例子——爬取51job发布的工作职位
2020/07/10 Python
PyTorch预训练Bert模型的示例
2020/11/17 Python
凯普林包包西班牙官网:Kipling西班牙
2019/04/12 全球购物
大学新生军训自我鉴定
2014/03/18 职场文书
乔迁之喜主持词
2014/03/27 职场文书
竞选学习委员演讲稿
2014/09/01 职场文书
财务会计求职信范文
2015/03/20 职场文书
班主任经验交流心得体会
2015/11/02 职场文书
Python使用OpenCV实现虚拟缩放效果
2022/02/28 Python