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
php防攻击代码升级版
Dec 29 PHP
.htaccess文件保护实例讲解
Feb 06 PHP
PHP和JAVA中的重载(overload)和覆盖(override) 介绍
Mar 01 PHP
基于ubuntu下nginx+php+mysql安装配置的具体操作步骤
Apr 28 PHP
php实现检查文章是否被百度收录
Jan 27 PHP
解析WordPress中控制用户登陆和判断用户登陆的PHP函数
Mar 01 PHP
yii2使用ajax返回json的实现方法
May 14 PHP
php简单计算年龄的方法(周岁与虚岁)
Dec 06 PHP
PHP将身份证正反面两张照片合成一张图片的代码
Apr 08 PHP
Yii 访问 Gii(脚手架)时出现 403 错误
Jun 06 PHP
PHP从零开始打造自己的MVC框架之类的自动加载实现方法详解
Jun 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中static,const与define的使用区别
2013/06/18 PHP
CentOS6.5 编译安装lnmp环境
2014/12/21 PHP
ThinkPHP3.2.1图片验证码实现方法
2016/08/19 PHP
Laravel如何自定义command命令浅析
2019/03/23 PHP
详细分析PHP 命名空间(namespace)
2020/06/30 PHP
精通Javascript系列之Javascript基础篇
2011/06/07 Javascript
解析John Resig Simple JavaScript Inheritance代码
2012/12/03 Javascript
jQuery循环滚动新闻列表示例代码
2014/06/17 Javascript
Python脚本后台运行的几种方式
2015/03/09 Javascript
JavaScript采用递归算法计算阶乘实例
2015/08/04 Javascript
JavaScript实现倒计时代码段Item1(非常实用)
2015/11/03 Javascript
JavaScript头像上传插件源码分享
2016/03/29 Javascript
微信小程序 定位到当前城市实现实例代码
2017/02/23 Javascript
微信小程序chooseImage的用法(从本地相册选择图片或使用相机拍照)
2018/08/22 Javascript
深入理解JS异步编程-Promise
2019/06/03 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
js实现抽奖的两种方法
2020/03/19 Javascript
[57:18]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#3VP VS VG
2016/03/03 DOTA
Python使用函数默认值实现函数静态变量的方法
2014/08/18 Python
使用url_helper简化Python中Django框架的url配置教程
2015/05/30 Python
python中pandas.DataFrame对行与列求和及添加新行与列示例
2017/03/12 Python
Python实现注册登录系统
2017/08/08 Python
Python实现基于二叉树存储结构的堆排序算法示例
2017/12/08 Python
微信跳一跳自动运行python脚本
2018/01/08 Python
python+matplotlib实现动态绘制图片实例代码(交互式绘图)
2018/01/20 Python
Python装饰器用法实例总结
2018/05/26 Python
python lxml中etree的简单应用
2019/05/10 Python
新版Pycharm中Matplotlib不会弹出独立的显示窗口的问题
2020/06/02 Python
python selenium xpath定位操作
2020/09/01 Python
Farfetch美国:奢侈品牌时尚购物平台
2019/05/02 全球购物
杭州龙健科技笔试题.net部分笔试题
2016/01/24 面试题
玩具公司的创业计划书
2013/12/31 职场文书
和谐拯救危机观后感
2015/06/15 职场文书
使用springboot暴露oracle数据接口的问题
2021/05/07 Oracle
python调试工具Birdseye的使用教程
2021/05/25 Python
Linux、ubuntu系统下查看显卡型号、显卡信息详解
2022/04/07 Servers