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 相关文章推荐
PHP MYSQL乱码问题,使用SET NAMES utf8校正
Nov 30 PHP
PHP之COOKIE支持详解
Sep 20 PHP
让Json更懂中文(JSON_UNESCAPED_UNICODE)
Oct 27 PHP
php打造属于自己的MVC框架
Mar 07 PHP
php5.2以下版本无json_decode函数的解决方法
May 25 PHP
PHP处理大量表单字段的便捷方法
Feb 07 PHP
php简单实现无限分类树形列表的方法
Mar 27 PHP
详解在PHP的Yii框架中使用行为Behaviors的方法
Mar 18 PHP
php自动载入类用法实例分析
Jun 24 PHP
PHP模型Model类封装数据库操作示例
Mar 14 PHP
PHP实现二维数组按照指定的字段进行排序算法示例
Apr 23 PHP
laravel5.1 ajax post 传值_token示例
Oct 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图片处理类 phpThumb参数用法介绍
2012/03/11 PHP
ThinkPHP6.0如何利用自定义验证规则规范的实现登陆
2020/12/16 PHP
Jquery ajaxStart()与ajaxStop()方法(实例讲解)
2013/12/18 Javascript
jquery 获取dom固定元素 添加样式的简单实例
2014/02/04 Javascript
使用coffeescript编写node.js项目的方法汇总
2015/08/05 Javascript
对jquery的ajax进行二次封装以及ajax缓存代理组件:AjaxCache详解
2016/04/11 Javascript
可输入文字查找ajax下拉框控件 ComBox的实现方法
2016/10/25 Javascript
详解js界面跳转与值传递
2016/11/22 Javascript
Bootstrap导航中表单简单实现代码
2017/03/06 Javascript
Angular2使用Angular-CLI快速搭建工程(二)
2017/05/21 Javascript
微信通过页面(H5)直接打开本地app的解决方法
2017/09/09 Javascript
vue axios数据请求get、post方法及实例详解
2018/09/11 Javascript
基于three.js实现的3D粒子动效实例代码
2019/04/09 Javascript
vue 项目build错误异常的解决方法
2019/04/22 Javascript
jquery实现简单拖拽效果
2020/07/20 jQuery
javascript实现时钟动画
2020/12/03 Javascript
菜鸟使用python实现正则检测密码合法性
2016/01/05 Python
深入理解Python中装饰器的用法
2016/06/28 Python
Python设置默认编码为utf8的方法
2016/07/01 Python
Python实现按特定格式对文件进行读写的方法示例
2017/11/30 Python
详解Python函数式编程—高阶函数
2019/03/29 Python
Python Web版语音合成实例详解
2019/07/16 Python
Flask教程之重定向与错误处理实例分析
2019/08/01 Python
学Python 3的理由和必要性
2019/11/19 Python
关于python中的xpath解析定位
2020/03/06 Python
Html5元素及基本语法详解
2016/08/02 HTML / CSS
美国保健品专家:Life Extension
2018/05/04 全球购物
Dodax奥地利:音乐、电影、书籍、玩具、电子产品等
2019/08/31 全球购物
Java面试题汇总
2015/12/06 面试题
我在伊朗长大观后感
2015/06/16 职场文书
交通安全教育主题班会
2015/08/12 职场文书
竞聘开场白方式有哪些?
2019/08/28 职场文书
python自动化调用百度api解决验证码
2021/04/13 Python
DjangoRestFramework 使用 simpleJWT 登陆认证完整记录
2021/06/22 Python
速龙x4-860k处理器相当于i几
2022/04/20 数码科技
Nginx配置之禁止指定IP访问
2022/05/02 Servers