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 相关文章推荐
修改Zend引擎实现PHP源码加密的原理及实践
Apr 14 PHP
CakePHP去除默认显示的标题及图标的方法
Oct 22 PHP
php下用cookie统计用户访问网页次数的代码
May 09 PHP
PHP IF ELSE简化/三元一次式的使用
Aug 22 PHP
PHP 杂谈《重构-改善既有代码的设计》之三 重新组织数据
Apr 09 PHP
php获取域名的google收录示例
Mar 24 PHP
浅谈PHP中单引号和双引号到底有啥区别呢?
Mar 04 PHP
php获取百度收录、百度热词及百度快照的方法
Apr 02 PHP
在PHP程序中使用Rust扩展的方法
Jul 03 PHP
PHP面向对象程序设计之命名空间与自动加载类详解
Dec 02 PHP
PHP串行化与反串行化实例分析
Dec 27 PHP
PHP编程计算日期间隔天数的方法
Apr 26 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
Zend的Registry机制的使用说明
2013/05/02 PHP
Yii2 加载css、js 载静态资源的方法
2017/03/10 PHP
鼠标经过的文本框textbox变色
2009/05/21 Javascript
实现web打印的各种方法介绍及实现代码
2013/01/09 Javascript
Javascript事件实例详解
2013/11/06 Javascript
禁止页面刷新让F5快捷键及右键都无效
2014/01/22 Javascript
ie8下修改input的type属性报错的解决方法
2014/09/16 Javascript
jQuery三级下拉列表导航菜单代码分享
2020/04/15 Javascript
jQuery progressbar通过Ajax请求实现后台进度实时功能
2016/10/11 Javascript
Vue学习笔记之表单输入控件绑定
2017/09/05 Javascript
Electron中实现大文件上传和断点续传功能
2018/10/28 Javascript
JavaScript实现世界各地时间显示
2020/09/07 Javascript
Python时区设置方法与pytz查询时区教程
2013/11/27 Python
pygame学习笔记(3):运动速率、时间、事件、文字
2015/04/15 Python
深入浅析ImageMagick命令执行漏洞
2016/10/11 Python
简单谈谈python中的语句和语法
2017/08/10 Python
在PyCharm中控制台输出日志分层级分颜色显示的方法
2019/07/11 Python
Python timer定时器两种常用方法解析
2020/01/20 Python
在python3中实现查找数组中最接近与某值的元素操作
2020/02/29 Python
Tensorflow之梯度裁剪的实现示例
2020/03/08 Python
python数据库编程 Mysql实现通讯录
2020/03/27 Python
matplotlib 曲线图 和 折线图 plt.plot()实例
2020/04/17 Python
Python configparser模块常用方法解析
2020/05/22 Python
浅谈Python中文件夹和python package包的区别
2020/06/01 Python
python属于跨平台语言码
2020/06/09 Python
python设置表格边框的具体方法
2020/07/17 Python
利用CSS3实现自定义滚动条代码分享
2016/08/18 HTML / CSS
HTML5 新标签全部总汇(推荐)
2016/06/13 HTML / CSS
使用Html5中的cavas画一面国旗
2019/09/25 HTML / CSS
wedgwood加拿大官网:1759年成立的英国国宝级陶瓷餐具品牌
2018/07/17 全球购物
计算机专业毕业生的自我评价
2013/11/18 职场文书
刚毕业大学生自荐信范文
2014/02/20 职场文书
防汛工作情况汇报
2014/10/28 职场文书
增值税发票丢失证明
2015/06/19 职场文书
SQL Server2019数据库之简单子查询的具有方法
2021/04/27 SQL Server
Mysql基础知识点汇总
2021/05/26 MySQL