原创:PHP内核研究 常量

来源:互联网 发布:淘宝上怎么搜买家 编辑:程序博客网 时间:2024/06/13 09:29
声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。
博客地址:PHP技术博客 在CSDN也会同步更新的哦.
欢迎转载,转载请注明出处 

常量

什么是常量.

常量就是不变的量.
先看看常量的结构

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


PHP定义常量如下

[php]

<?php

define('TEST',1);

[/php]

很简单 .定义了一个常量

那在内核里都做了什么?

打开 zend/zend_builtin_functions.c  PHP的内置函数都在这里

找到 ZEND_FUNCTION(define)

代码如下

[c]

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;
}
}
[/c]

既然说了define 那就肯定要说说defined了
defined用来检测 常量是否已经定义
这个其实很简单 代码如下

[c]
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;
}
}
[/c]


主要的工作在 zend_get_constant_ex这个函数里

[c]
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);
}
[/c]

define就是将创建的常量 放在EG(zend_constants)里
defined就是在EG(zend_constants)去递归查找


原创粉丝点击