• php源码zend_do_begin_namespace函数详解


    void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC) /* {{{ */
    {
        char *lcname;
    
        /* handle mixed syntax declaration or nested namespaces */
        if (!CG(has_bracketed_namespaces)) {
            if (CG(current_namespace)) {
                /* previous namespace declarations were unbracketed */
                if (with_bracket) {
                    zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations");
                }
            }
        } else {
            /* previous namespace declarations were bracketed */
            if (!with_bracket) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations");
            } else if (CG(current_namespace) || CG(in_namespace)) {
                zend_error_noreturn(E_COMPILE_ERROR, "Namespace declarations cannot be nested");
            }
        }
    
        if (((!with_bracket && !CG(current_namespace)) || (with_bracket && !CG(has_bracketed_namespaces))) && CG(active_op_array)->last > 0) {
            /* ignore ZEND_EXT_STMT and ZEND_TICKS */
            int num = CG(active_op_array)->last;
            while (num > 0 &&
                   (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT ||
                    CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) {
                --num;
            }
            if (num > 0) {
                zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script");
            }
        }
    
        CG(in_namespace) = 1;
        if (with_bracket) {
            CG(has_bracketed_namespaces) = 1;
        }
    
        if (name) {
            lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant));
            if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) &&
                  !memcmp(lcname, "self", sizeof("self")-1)) ||
                ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) &&
                  !memcmp(lcname, "parent", sizeof("parent")-1))) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant));
            }
            efree(lcname);
    
            if (CG(current_namespace)) {
                zval_dtor(CG(current_namespace));
            } else {
                ALLOC_ZVAL(CG(current_namespace));
            }
            *CG(current_namespace) = name->u.constant;
        } else {
            if (CG(current_namespace)) {
                zval_dtor(CG(current_namespace));
                FREE_ZVAL(CG(current_namespace));
                CG(current_namespace) = NULL;
            }
        }
    
        if (CG(current_import)) {
            zend_hash_destroy(CG(current_import));
            efree(CG(current_import));
            CG(current_import) = NULL;
        }
    
        if (CG(current_import_function)) {
            zend_hash_destroy(CG(current_import_function));
            efree(CG(current_import_function));
            CG(current_import_function) = NULL;
        }
    
        if (CG(current_import_const)) {
            zend_hash_destroy(CG(current_import_const));
            efree(CG(current_import_const));
            CG(current_import_const) = NULL;
        }
    
        if (CG(doc_comment)) {
            efree(CG(doc_comment));
            CG(doc_comment) = NULL;
            CG(doc_comment_len) = 0;
        }
    }

    解析

    该函数是在语法解析的时候,编译器扫描到namespace xxx;namespace xxx{};namespace {};三种形式的时候调用

    zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC)的参数name为znode结构的命名空间名称,with_bracket表示是否为括号型的命名空间(1表示带括号)

    函数刚开始会判断代码中是否同时用了不带括号和带括号的形式,如果是这样的话,会抛出一个编译类型错误:Cannot mix bracketed namespace declarations with unbracketed namespace declaration

    例如

     
    

    或者命名空间被嵌套使用的话,会抛出一个编译类型错误:Namespace declarations cannot be nested

    例如

     
    

    且命名空间不能为self和parent的任何大小写形式,否则会抛出一个编译类型错误:Cannot use xxx as namespace name

    例如

     
    

    命名空间的错误检查完了以后,就是下面的工作了

    如果命名空间是有名称值的,将会把名称存入*CG(current_namespace)中

    CG(current_namespace)等价于compile_globals.current_namespace

    其他细节不做讲解,请读者自行查看

  • 相关阅读:
    王道书 P150 T20 + 拓展(表达式树的计算)
    几乎所有的互联网公司都在进行一场脱虚向实的全新嬗变
    功能测试:核心原理、挑战以及解决之道
    保证数据库质量安全:从0开始的数据库测试
    简单介绍Map中的getOrDefault
    react学习3 生命周期
    市政管理学考试复习资料
    uniapp父组件使用prop将异步的数据传给子组件
    【华为OD机试真题 python】 城市聚集度【2022 Q4 | 200分】
    Django笔记十之values_list指定字段取值及distinct去重处理
  • 原文地址:https://blog.csdn.net/weixin_67271870/article/details/127544725