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
其他细节不做讲解,请读者自行查看
转载请注明原处