Global变量

Global变量

1,创建一个扩展

./ext_skel --extname=global

2,扩展global变量

/*定义global变量*/
ZEND_BEGIN_MODULE_GLOBALS(global)
    long  counter;
    char *name;
    int name_len;
ZEND_END_MODULE_GLOBALS(global)

ZEND_DECLARE_MODULE_GLOBALS(global);//申明变量

GLOBAL_G(name); //获取global变量的值

GLOBAL_G(counter) = 10; //给global变量赋值

3,POST|GET|COOKIE|SERVER|ENV|REQUEST|FILES全局变量

#php-fpm 生成 POST|GET|COOKIE|SERVER|ENV|REQUEST|FILES全局变量的流程
php_cgi_startup() -> php_module_startup() -> php_startup_auto_globals() -> 保存变量到symbol_table符号表

php_cgi_startup()在 fpm/fpm/fpm_main.c中定义
php_module_startup() 在main/main.c中定义
php_startup_auto_globals() 在main/php_variables.h中定义
zend_hash_update(&EG(symbol_table), "_GET", sizeof("_GET") + 1, &vars, sizeof(zval *), NULL);

/* 读取$_SERVER变量 */
static PHP_FUNCTION(print_server_vars) {
    zval **val;
    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {
        RETURN_ZVAL(*val, 1, 0);
    }else{
     RETURN_FALSE;
    }
}

/* 读取$_SERVER[$name] */

ZEND_BEGIN_ARG_INFO(print_server_var_arginfo, 0)
    ZEND_ARG_INFO(0, "name")
ZEND_END_ARG_INFO()

static PHP_FUNCTION(print_server_var) {
    char *name;
    int name_len;
    zval **val;
    HashTable *ht_vars = NULL;
    HashPosition pos;
    zval **ret_val;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }

    if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {
        ht_vars = Z_ARRVAL_PP(val);

        //此处需传入大于name长度+1的值,因为字符串值后面需要'\0'

        if (zend_hash_find(ht_vars, name, name_len+1, (void **)&ret_val) == SUCCESS) {              RETURN_STRING(Z_STRVAL_PP(ret_val), 0);
        }else{
            RETURN_NULL();
        }
    }else{
        RETURN_NULL();
    }
}

4,$GLOBALS变量

/*添加globals变量*/
static PHP_FUNCTION(add_globals_vars) {
    SET_VAR_LONG("_LONG", 10); //添加long变量
    SET_VAR_DOUBLE("_DOUBLE", 20.5); //添加double变量
    SET_VAR_STRING("_STRING", "string"); //添加string变量

    zval *arr;
    MAKE_STD_ZVAL(arr);
    array_init(arr);
    add_assoc_string(arr, "e", "hello", 1);
    ZEND_SET_GLOBAL_VAR("_ARRS", arr); //添加zval变量
}

/*添加globals字符串变量*/

5,相关宏

/* 设置global变量 */
#define ZEND_SET_GLOBAL_VAR(name, var)   ZEND_SET_SYMBOL(&EG(symbol_table), name, var)

#define ZEND_SET_GLOBAL_VAR_WITH_LENGTH(name, name_length, var, _refcount, _is_ref)
    ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), name, name_length, var, _refcount, _is_ref)

/ *设置string类型的global变量 */   
#define SET_VAR_STRING(n, v) {  { zval *var;
                                ALLOC_ZVAL(var);
                                ZVAL_STRING(var, v, 0);
                                ZEND_SET_GLOBAL_VAR(n, var);}
                        }

#define SET_VAR_STRINGL(n, v, l) {  {zval *var;
                                    ALLOC_ZVAL(var);
                                    ZVAL_STRINGL(var, v, l, 0);
                                    ZEND_SET_GLOBAL_VAR(n, var);}
                            }

/* 设置long类型的global变量 */
#define SET_VAR_LONG(n, v)  {{zval *var;    
                            ALLOC_ZVAL(var);
                            ZVAL_LONG(var, v);
                            ZEND_SET_GLOBAL_VAR(n, var);}
                        }

/* 设置double类型的global变量 */
#define SET_VAR_DOUBLE(n, v) {{ zval *var;  
                                ALLOC_ZVAL(var);
                                ZVAL_DOUBLE(var, v);
                                ZEND_SET_GLOBAL_VAR(n, 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)) {       
        Z_SET_REFCOUNT_P(var, Z_REFCOUNT_PP(orig_var));
        Z_SET_ISREF_P(var);                 
        if (_refcount) {                    
            Z_SET_REFCOUNT_P(var, Z_REFCOUNT_P(var) + _refcount - 1);
        }                                   
        zval_dtor(*orig_var);               
        **orig_var = *(var);                
        FREE_ZVAL(var);                     
    } else {                                
        Z_SET_ISREF_TO_P(var, _is_ref);     
        if (_refcount) {                    
            Z_SET_REFCOUNT_P(var, _refcount);
        }                                   
        zend_hash_update(symtable, (name), (name_length), &(var), sizeof(zval *), NULL);
    }                                       
}