• php源码zend_do_begin_namespace函数详解


    version:5.6.21

    file:Zend/zend_compile.c

    line:7055-7152

    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

    例如

    <?php
    namespace a;
    
    echo "I belong to namespace a";
    
    namespace b {
        echo "I'm from namespace b";
    }

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

    例如

    <?php
    namespace b {
        namespace a{
            echo "I belong to namespace a";
        }
    }

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

    例如

    <?php
    namespace sElf;
    
    echo "I belong to namespace sElf";

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

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

    CG(current_namespace)等价于compile_globals.current_namespace

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

  • 相关阅读:
    观念
    DB2 SQL Error: SQLCODE=104, SQLSTATE=42601
    DB2 SQL Error: SQLCODE=302, SQLSTATE=22001
    Flex Socket编程:安全错误:Error #2048
    JSONP跨域的原理解析
    java 学习
    C语言报错 error C2143: 语法错误 : 缺少“]”(在“;”的前面)
    分享:模版方法,策略模式和状态模式之间的区别
    OracleOrSqlServer 递归查询
    asp.net页生命周期阶段
  • 原文地址:https://www.cnblogs.com/xiaozong/p/6298127.html
Copyright © 2020-2023  润新知