设为首页 收藏本站
查看: 1022|回复: 0

[经验分享] 原创:PHP内核研究 常量

[复制链接]

尚未签到

发表于 2017-3-27 07:59:08 | 显示全部楼层 |阅读模式
声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。

博客地址: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)去递归查找

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-355826-1-1.html 上篇帖子: php中的header函数 下篇帖子: PHP入门知识点
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表