甩祸 发表于 2017-3-27 07:59:08

原创:PHP内核研究 常量

声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。

博客地址:PHP技术博客在CSDN也会同步更新的哦.

欢迎转载,转载请注明出处


常量

什么是常量.

常量就是不变的量.

先看看常量的结构



typedef struct _zend_constant {
      zval value;//zval类型
      int flags;//标示 是否大小写敏感
      char *name;//常量名称
      uint name_len;//长度
      int module_number;//标示是用户定义的常量 不是系统常量
} zend_constant;




PHP定义常量如下
http://imsiren.com/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif




<?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 == '\\') {
                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 = '\\';
                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)去递归查找
页: [1]
查看完整版本: 原创:PHP内核研究 常量