php 常量
常量存储位置
1 EG(zend_constants)
常量的内部结构
在Zend/zend_constants.h文件的33行可以看到如下所示的结构定义。在常量的结构中,除了与变量一样的zval结构,它还包括属于常量的标记,常量名以及常量所在的模块号
typedef struct _zend_constant { zval value;/* zval结构,PHP内部变量的存储结构,在第一小节有说明 */ int flags; /* 常量的标记如 CONST_PERSISTENT | CONST_CS |CONST_CT_SUBST */ char *name;/* 常量名称 */ uint name_len; int module_number;/* 模块号 */ } zend_constant;
flags取值:
CONST_PERSISTENT:表示这个常量需要持久化。这里的持久化内存申请时的持久化是一个概念,非持久常量会在请求结束时释放该常量。如果是非持久常量,会在RSHUTDOWN阶段就将该常量释放,否则只会在MSHUTDOWN阶段将内存释放,在用户空间,也就是用户定义的常量都是非持久化的,通常扩展和内核定义的常量会设置为持久化,因为如果常量被释放了,而下次请求又需要使用这个常量,该常量就必须在请求时初始化一次,而对于常量这些不变的量来说就是个没有意义的重复计算。
CONST_CT_SUBST: /* Allow compile-time substitution */(在编译时可被替换)。
CONST_CS: /* Case Sensitive */ 大小写敏感
define函数的实现
define是PHP的内置函数,在Zend/zend_builtin_functions.c文件中定义了此函数的实现
/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false) Define a new constant */ ZEND_FUNCTION(define) { char *name; int name_len; zval *val; zval *val_free = NULL; zend_bool non_cs = 0; int case_sensitive = CONST_CS; // 是否大小写敏感,默认为1 zend_constant c; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) { return; } if(non_cs) { case_sensitive = 0; } /* class constant, check if there is name and make sure class is valid & exists */ if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) { zend_error(E_WARNING, "Class constants cannot be defined or redefined"); RETURN_FALSE; } repeat: switch (Z_TYPE_P(val)) { case IS_LONG: case IS_DOUBLE: case IS_STRING: case IS_BOOL: case IS_RESOURCE: case IS_NULL: break; case IS_OBJECT: if (!val_free) { if (Z_OBJ_HT_P(val)->get) { val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC); goto repeat; } else if (Z_OBJ_HT_P(val)->cast_object) { ALLOC_INIT_ZVAL(val_free); if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) { val = val_free; break; } } } /* no break */ default: zend_error(E_WARNING,"Constants may only evaluate to scalar values"); if (val_free) { zval_ptr_dtor(&val_free); } RETURN_FALSE; } c.value = *val; zval_copy_ctor(&c.value); if (val_free) { zval_ptr_dtor(&val_free); } c.flags = case_sensitive; /* non persistent */ c.name = zend_strndup(name, name_len); c.name_len = name_len+1; c.module_number = PHP_USER_CONSTANT; if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) { RETURN_TRUE; } else { RETURN_FALSE; } } /* }}} */
其实现上是一个将传递的参数传递给新建的zend_constant结构,并将这个结构体注册到常量列表中的过程。
例子:标准常量TRUE的定义
/*声明结构体*/ zend_constant c; /*结构体赋值*/ c.flags = CONST_PERSISTENT | CONST_CT_SUBST; c.module_number = 0; c.name = zend_strndup(ZEND_STRL("TRUE")); c.name_len = sizeof("TRUE"); c.value.value.lval = 1; c.value.type = IS_BOOL; /*注册结构体*/ zend_register_constant(&c TSRMLS_CC);
常量的销毁
非持久化常量在request请求结束时销毁,具体销毁操作在:php_request_shutdown()->zend_deactivate()->shutdown_executor()->clean_non_persistent_constants()。
1 void clean_non_persistent_constants(TSRMLS_D) 2 { 3 if (EG(full_tables_cleanup)) { 4 zend_hash_apply(EG(zend_constants), (apply_func_t) clean_non_persistent_constant_full TSRMLS_CC); 5 } else { 6 zend_hash_reverse_apply(EG(zend_constants), (apply_func_t) clean_non_persistent_constant TSRMLS_CC); 7 } 8 }
for remember