常量存儲位置php
1 EG(zend_constants)
常量的內部結構
在Zend/zend_constants.h文件的33行能夠看到以下所示的結構定義。在常量的結構中,除了與變量同樣的zval結構,它還包括屬於常量的標記,常量名以及常量所在的模塊號app
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 */(在編譯時可被替換)。ui
CONST_CS: /* Case Sensitive */ 大小寫敏感lua
define函數的實現
define是PHP的內置函數,在Zend/zend_builtin_functions.c文件中定義了此函數的實現spa
/* {{{ 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結構,並將這個結構體註冊到常量列表中的過程。scala
例子:標準常量TRUE的定義code
/*聲明結構體*/ 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);
常量的銷燬blog
非持久化常量在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 }