当前位置: 首页 > 编程笔记 >

PHP源码分析之变量的存储过程分解

骆文华
2023-03-14
本文向大家介绍PHP源码分析之变量的存储过程分解,包括了PHP源码分析之变量的存储过程分解的使用技巧和注意事项,需要的朋友参考一下

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. 如果全局符号表不存在该变量或者存在该变量但不是引用变量,则直接改变其值。

 类似资料:
  • 本文向大家介绍MySQL 声明变量及存储过程分析,包括了MySQL 声明变量及存储过程分析的使用技巧和注意事项,需要的朋友参考一下 声明变量 设置全局变量 set @a='一个新变量'; 在函数和储存过程中使用的变量declear declear a int unsigned default 1; 这种变量需要设置变量类型 而且只存在在 begin..end 这段之内 select .. into

  • 本文向大家介绍Mybatis源码分析之存储过程调用和运行流程,包括了Mybatis源码分析之存储过程调用和运行流程的使用技巧和注意事项,需要的朋友参考一下 这一篇我们学习一下Mybatis调用存储过程的使用和运行流程。首先我们先创建一个简单的存储过程 这个存储过程的含义其实比较简单的,就是输入age,然后执行select count(*) from users where users.age =

  • 本文向大家介绍php调用mysql存储过程实例分析,包括了php调用mysql存储过程实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例分析了php调用mysql存储过程的方法。分享给大家供大家参考。具体分析如下: Mysql存储过程创建语法,代码如下: CREATE PROCEDURE和CREATE FUNCTION : 当我们看完以后,就可以开始写一些简单的存储过程了,首先建立存储过程

  • ethereum的虚拟机源码所有部分在core/vm下。 去除测试总共有24个源码文件。 整个vm调用的入口在go-ethereum/core/state_transaction.go中。 我们主要是为了分析虚拟机源码,所以关于以太坊是如何进行交易转账忽略过去。 从上面的截图我们可以看出, 当以太坊的交易中to地址为nil时, 意味着部署合约, 那么就会调用evm.Create方法。 否则调用了e

  • 本文向大家介绍JUC之Semaphore源码分析,包括了JUC之Semaphore源码分析的使用技巧和注意事项,需要的朋友参考一下 Semaphore 主要用于限量控制并发执行代码的工具类, 其内部通过 一个 permit 来进行定义并发执行的数量。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 区块链技术是计算机技术与金融技术交融的成功创新,被认为是极具潜力的分布式账本平台的核心技术。如果你还不了解区块链,可以阅读 区块链技术指南。