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 相关文章推荐
第十三节--对象串行化
Nov 16 PHP
PHP Array交叉表实现代码
Aug 05 PHP
php生成RSS订阅的方法
Feb 13 PHP
PHP实现WebService的简单示例和实现步骤
Mar 27 PHP
php给一组指定关键词添加span标签的方法
Mar 31 PHP
SSO单点登录的PHP实现方法(Laravel框架)
Mar 23 PHP
CI框架简单邮件发送类实例
May 18 PHP
Thinkphp框架 表单自动验证登录注册 ajax自动验证登录注册
Dec 27 PHP
ZendFramework2连接数据库操作实例
Apr 18 PHP
Laravel框架生命周期与原理分析
Jun 12 PHP
thinkphp5引入公共部分header、footer的方法详解
Sep 14 PHP
PHP使用Redis队列执行定时任务实例讲解
Mar 24 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 Undefined index的问题
2009/06/01 PHP
php 数组的一个悲剧?
2011/05/11 PHP
php数组函数序列之array_slice() - 在数组中根据条件取出一段值,并返回
2011/11/07 PHP
今天你说520了吗?不仅有php表白书还有java表白神器
2016/05/20 PHP
php unicode编码和字符串互转的方法
2020/08/12 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
2018/06/13 PHP
让任务管理器中的CPU跳舞的js代码
2008/11/01 Javascript
jquery中输入验证中一个不错的效果
2010/08/21 Javascript
javascript数组操作总结和属性、方法介绍
2014/04/05 Javascript
js简单实现竖向tab选项卡的方法
2015/05/04 Javascript
JavaScript去除数组里重复值的方法
2015/07/13 Javascript
使用Node.js处理前端代码文件的编码问题
2016/02/16 Javascript
工厂模式在JS中的实践
2017/01/18 Javascript
10道典型的JavaScript面试题
2017/03/22 Javascript
Vue 实用分页paging实例代码
2017/04/12 Javascript
基于vue实现swipe分页组件实例
2017/05/25 Javascript
基于vue 动态加载图片src的解决方法
2018/02/05 Javascript
JavaScript实现电灯开关小案例
2020/03/30 Javascript
[51:50]完美世界DOTA2联赛 Magma vs GXR 第一场 11.07
2020/11/10 DOTA
使用python统计文件行数示例分享
2014/02/21 Python
在Python中使用PIL模块对图片进行高斯模糊处理的教程
2015/05/05 Python
python黑魔法之参数传递
2016/02/12 Python
轻松掌握python设计模式之策略模式
2016/11/18 Python
Python实现将sqlite数据库导出转成Excel(xls)表的方法
2017/07/17 Python
python中列表和元组的区别
2017/12/18 Python
Python unittest 自动识别并执行测试用例方式
2020/03/09 Python
美国唇部护理专家:Sara Happ
2019/06/19 全球购物
销售代表求职自荐信
2013/10/01 职场文书
毕业生医学检验求职信
2013/10/16 职场文书
医学生自我鉴定范文
2013/11/08 职场文书
大学生入党思想汇报
2014/01/01 职场文书
个人总结与自我评价
2015/02/14 职场文书
2015年乡镇工作总结范文
2015/04/22 职场文书
生日祝酒词大全
2015/08/10 职场文书
nginx如何将http访问的网站改成https访问
2021/03/31 Servers
python实现双向链表原理
2022/05/25 Python