Home >Backend Development >PHP Tutorial >【PHP内核学习】global关键字的解析过程分析

【PHP内核学习】global关键字的解析过程分析

WBOY
WBOYOriginal
2016-06-23 13:57:371100browse

本文github地址:

https://github.com/wusuopubupt/phpLib/blob/master/global%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84%E8%A7%A3%E6%9E%90%E8%BF%87%E7%A8%8B%E5%88%86%E6%9E%90


          <p class="sycode">              |=-----------------------------------------------------------------------=|          </p>          <p class="sycode">              |=--------------------=[ global关键字的解析过程分析 ]=-------------------=|          </p>          <p class="sycode">              |=-----------------------------------------------------------------------=|          </p>          <p class="sycode">              |=--------------------------=[  by d4shman  ]=---------------------------=|          </p>          <p class="sycode">              |=-----------------------------------------------------------------------=|          </p>          <p class="sycode">              |=-------------------------=[  May 8, 2014  ]=---------------------------=|          </p>          <p class="sycode">              |=-----------------------------------------------------------------------=|          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              [目录]          </p>          <p class="sycode">              0x01 词法分析           </p>          <p class="sycode">              0X02 语法分析          </p>          <p class="sycode">              0X03 解释执行          </p>          <p class="sycode">              0X04 参考文献          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              0x01 词法分析          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              d4shman@gentoo# vi /php-dev/php-5.4.8/Zend/zend_language_scanner.l          </p>          <p class="sycode">              找到global:          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  <st_in_scripting>"global" {          </st_in_scripting></p>          <p class="sycode">                      return T_GLOBAl;          </p>          <p class="sycode">                  }          </p>          <p class="sycode">              发现返回一个token T_GLOBAL          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              0X02 语法分析          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              通过token T_GLOBAL来到zend_language_parser.y找到:          </p>          <p class="sycode">                  |   T_GLOBAL global_var_list ';'          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  global_var_list:          </p>          <p class="sycode">                          global_var_list ',' global_var  { zend_do_fetch_global_variable(&$3, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); }          </p>          <p class="sycode">                      |   global_var                      { zend_do_fetch_global_variable(&$1, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); }          </p>          <p class="sycode">                  ;          </p>          <p class="sycode">              上面的$3指的是global_val,可以看到,对于全局变量,语法分析器调用的是Zend引擎          </p>          <p class="sycode">              的zend_do_fetch_globa_variable函数。此函数的声明在Zend/zend_compile.c          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              0X03 解释执行          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  在Zend/zend_compile.c中找到zend_do_fetch_global_variable函数定义:          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  void zend_do_fetch_global_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC)           </p>          <p class="sycode">                  {          </p>          <p class="sycode">                      zend_op *opline;          </p>          <p class="sycode">                      znode lval;          </p>          <p class="sycode">                      znode result;          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              		/*如果变量类型是常量且不是字符串,则将其转化成字符串类型*/          </p>          <p class="sycode">                      if (varname->op_type == IS_CONST) {            </p>          <p class="sycode">                          if (Z_TYPE(varname->u.constant) != IS_STRING) {          </p>          <p class="sycode">                              convert_to_string(&varname->u.constant);          </p>          <p class="sycode">                          }          </p>          <p class="sycode">                      }          </p>          <p class="sycode">                            </p>          <p class="sycode">                      opline = get_next_op(CG(active_op_array) TSRMLS_CC); /* CG: compile_global */          </p>          <p class="sycode">                      opline->opcode = ZEND_FETCH_W;      /* 默认的模式必须是Write */          </p>          <p class="sycode">                      opline->result_type = IS_VAR;          </p>          <p class="sycode">                      opline->result.var = get_temporary_variable(CG(active_op_array));          </p>          <p class="sycode">                      SET_NODE(opline->op1, varname);          </p>          <p class="sycode">                      if (opline->op1_type == IS_CONST) {          </p>          <p class="sycode">                          CALCULATE_LITERAL_HASH(opline->op1.constant);          </p>          <p class="sycode">                      }          </p>          <p class="sycode">                      SET_UNUSED(opline->op2);          </p>          <p class="sycode">                      opline->extended_value = fetch_type;          </p>          <p class="sycode">                      GET_NODE(&result, opline->result);          </p>          <p class="sycode">                            </p>          <p class="sycode">                      if (varname->op_type == IS_CONST) {          </p>          <p class="sycode">                          zval_copy_ctor(&varname->u.constant);          </p>          <p class="sycode">                      }          </p>          <p class="sycode">              		/* Relies on the fact that the default fetch is BP_VAR_W */          </p>          <p class="sycode">                      fetch_simple_variable(&lval, varname, 0 TSRMLS_CC);           </p>          <p class="sycode">                            </p>          <p class="sycode">                      zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC);          </p>          <p class="sycode">                      CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result_type |= EXT_TYPE_UNUSED;          </p>          <p class="sycode">                  }          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  上面的代码确认了opcode为ZEND_FETCH_W外,还执行了zend_do_assign_ref函数。zend_do_assign_ref函数中          </p>          <p class="sycode">              有这么一个关键语句:          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  opline->opcode = ZEND_ASSIGN_REF;          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  由此可知,语法分析过程中,实际执行了2个opcode: ZEND_FETCH_W和ZEND_ASSIGN_REF,在zend_vm_opcodes.h          </p>          <p class="sycode">              中发现,它们对应的opcode分别是83和39。而计算最后调用的方法是(定义在zend_execute.c:):          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  计算后(///////////我没搞清楚是怎么计算出的//////////),得到调用的函数是:          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  static int ZEND_FASTCALL  ZEND_FETCH_W_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)          </p>          <p class="sycode">                  {          </p>          <p class="sycode">                      return zend_fetch_var_address_helper_SPEC_CV(BP_VAR_W, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);          </p>          <p class="sycode">                  }	          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  在zend_fetch_var_address_helper_SPEC_CV中调用如下代码获取符号表:          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), type, varname TSRMLS_CC);          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              	zend_get_target_symbol_table函数的实现如下(在):          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  static inline HashTable *zend_get_target_symbol_table(int fetch_type TSRMLS_DC)          </p>          <p class="sycode">                  {          </p>          <p class="sycode">                      switch (fetch_type) {          </p>          <p class="sycode">                          case ZEND_FETCH_LOCAL:            </p>          <p class="sycode">                              if (!EG(active_symbol_table)) {          </p>          <p class="sycode">                                  zend_rebuild_symbol_table(TSRMLS_C);          </p>          <p class="sycode">                              }          </p>          <p class="sycode">                              return EG(active_symbol_table);          </p>          <p class="sycode">                              break;          </p>          <p class="sycode">                          case ZEND_FETCH_GLOBAL:          </p>          <p class="sycode">                          case ZEND_FETCH_GLOBAL_LOCK:          </p>          <p class="sycode">                              return &EG(symbol_table); /*返回global 变量符号表的地址*/          </p>          <p class="sycode">                              break;          </p>          <p class="sycode">                          case ZEND_FETCH_STATIC:          </p>          <p class="sycode">                              if (!EG(active_op_array)->static_variables) {          </p>          <p class="sycode">                                  ALLOC_HASHTABLE(EG(active_op_array)->static_variables);          </p>          <p class="sycode">                                  zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);          </p>          <p class="sycode">                              }          </p>          <p class="sycode">                              return EG(active_op_array)->static_variables;          </p>          <p class="sycode">                              break;          </p>          <p class="sycode">                          EMPTY_SWITCH_DEFAULT_CASE()          </p>          <p class="sycode">                      }          </p>          <p class="sycode">                      return NULL;          </p>          <p class="sycode">                  }          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              	通过代码可以看到,当传递过来的fetch_type是ZEND_FETCH_GLOBAL(_LOCK)时,函数使用EG(excutor_global)宏          </p>          <p class="sycode">              返回了global变量的符号表地址。          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                  以上就是global变量解析执行的整个过程。          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              0X04 参考文献          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              《深入理解PHP内核》          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">              <br>          </p>          <p class="sycode">                            </p>

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn