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 }

 

posted @ 2018-08-07 17:32  DearMrLi  阅读(132)  评论(0编辑  收藏  举报