常量
什么是常量.
常量就是不变的量.
先看看常量的结构
- typedef struct _zend_constant {
- zval value;//zval类型
- int flags;//标示 是否大小写敏感
- char *name;//常量名称
- uint name_len;//长度
- int module_number;//标示是用户定义的常量 不是系统常量
- } zend_constant;
PHP定义常量如下
- <?php
- define('TEST',1);
很简单 .定义了一个常量
那在内核里都做了什么?
打开 zend/zend_builtin_functions.c PHP的内置函数都在这里
找到 ZEND_FUNCTION(define)
代码如下
- ZEND_FUNCTION(define)
- {
- char *name;
- int name_len;
- zval *val;
- zval *val_free = NULL;
- zend_bool non_cs = 0;
- int case_sensitive = CONST_CS;
- zend_constant c;//这个是常量的struct
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
- return;
- }
- if(non_cs) {//define第三个参数的作用,大小写是否敏感 如果为真 大小写不敏感
- case_sensitive = 0;
- }
- //PHP5.3新特性:类常量,暂不做介绍
- 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);//完全拷贝 因为val是zval类型,除了value还有其他属性,用这个宏完全拷贝过来
- if (val_free) {
- zval_ptr_dtor(&val_free);
- }
- c.flags = case_sensitive; //大小写敏感?
- c.name = zend_strndup(name, name_len); //拷贝name
- 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;
- }
- }
既然说了define 那就肯定要说说defined了
defined用来检测 常量是否已经定义
这个其实很简单 代码如下
- ZEND_FUNCTION(defined)
- {
- char *name;
- int name_len;
- zval c;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
- return;
- }
- if (zend_get_constant_ex(name, name_len, &c, NULL, ZEND_FETCH_CLASS_SILENT TSRMLS_CC)) {//找到了
- zval_dtor(&c); //释放zval.value的内存
- RETURN_TRUE;
- } else {//没找到
- RETURN_FALSE;
- }
- }
主要的工作在 zend_get_constant_ex这个函数里
- ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC)
- {
- zend_constant *c; //常量类型
- int retval = 1;
- char *colon;
- zend_class_entry *ce = NULL;
- char *class_name;
- zval **ret_constant;
- /* Skip leading \\ */
- if (name[0] == '\\') {
- name += 1;
- name_len -= 1;
- }
- if ((colon = zend_memrchr(name, ':', name_len)) &&
- colon > name && (*(colon - 1) == ':')) { //类常量 暂不做介绍
- int class_name_len = colon - name - 1;
- int const_name_len = name_len - class_name_len - 2;
- char *constant_name = colon + 1;
- char *lcname;
- class_name = estrndup(name, class_name_len);
- lcname = zend_str_tolower_dup(class_name, class_name_len);
- if (!scope) {
- if (EG(in_execution)) {
- scope = EG(scope);
- } else {
- scope = CG(active_class_entry);
- }
- }
- if (class_name_len == sizeof("self")-1 &&
- !memcmp(lcname, "self", sizeof("self")-1)) {
- if (scope) {
- ce = scope;
- } else {
- zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
- retval = 0;
- }
- efree(lcname);
- } else if (class_name_len == sizeof("parent")-1 &&
- !memcmp(lcname, "parent", sizeof("parent")-1)) {
- if (!scope) {
- zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
- } else if (!scope->parent) {
- zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
- } else {
- ce = scope->parent;
- }
- efree(lcname);
- } else if (class_name_len == sizeof("static")-1 &&
- !memcmp(lcname, "static", sizeof("static")-1)) {
- if (EG(called_scope)) {
- ce = EG(called_scope);
- } else {
- zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
- }
- efree(lcname);
- } else {
- efree(lcname);
- ce = zend_fetch_class(class_name, class_name_len, flags TSRMLS_CC);
- }
- if (retval && ce) {
- if (zend_hash_find(&ce->constants_table, constant_name, const_name_len+1, (void **) &ret_constant) != SUCCESS) {
- retval = 0;
- if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
- zend_error(E_ERROR, "Undefined class constant '%s::%s'", class_name, constant_name);
- }
- }
- } else if (!ce) {
- retval = 0;
- }
- efree(class_name);
- goto finish;
- }
- //普通常量 colon为反斜线之前的字符串
- if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) {
- /* compound constant name */
- int prefix_len = colon - name;
- int const_name_len = name_len - prefix_len - 1;
- char *constant_name = colon + 1;
- char *lcname;
- int found_const = 0;
- lcname = zend_str_tolower_dup(name, prefix_len);
- /* Check for namespace constant */
- /* Concatenate lowercase namespace name and constant name */
- lcname = erealloc(lcname, prefix_len + 1 + const_name_len + 1);
- lcname[prefix_len] = '\\';
- memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1);
- //查找常量
- if (zend_hash_find(EG(zend_constants), lcname, prefix_len + 1 + const_name_len + 1, (void **) &c) == SUCCESS) {
- found_const = 1;//找到了
- } else {//没找到
- //转换为小写重新查找
- zend_str_tolower(lcname + prefix_len + 1, const_name_len);
- if (zend_hash_find(EG(zend_constants), lcname, prefix_len + 1 + const_name_len + 1, (void **) &c) == SUCCESS) {//找到了
- if ((c->flags & CONST_CS) == 0) {
- found_const = 1;
- }
- }
- }
- efree(lcname);
- if(found_const) {
- *result = c->value;
- zval_update_constant_ex(&result, (void*)1, NULL TSRMLS_CC);
- zval_copy_ctor(result);
- Z_SET_REFCOUNT_P(result, 1);
- Z_UNSET_ISREF_P(result);
- return 1;
- }
- /* name requires runtime resolution, need to check non-namespaced name */
- if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
- name = constant_name;
- name_len = const_name_len;
- return zend_get_constant(name, name_len, result TSRMLS_CC);
- }
- retval = 0;
- finish:
- if (retval) {
- zval_update_constant_ex(ret_constant, (void*)1, ce TSRMLS_CC);
- *result = **ret_constant;
- zval_copy_ctor(result);
- INIT_PZVAL(result);
- }
- return retval;
- }
- return zend_get_constant(name, name_len, result TSRMLS_CC);
- }
define就是将创建的常量 放在EG(zend_constants)里
defined就是在EG(zend_constants)去递归查找