快速业务通道

PHP源码分析之Global关键字

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-05-23

 

  闲来无事,就系统的从PHP的词法分析,语法分析,opcodes生成,执行,整个流程,详细的分析了global关键字的实现。

  当你在脚本中写下:

 

  <?php

  $var = "laruence";

  function sample(){

  global $var;

  }

  ?>

 

  的时候,你知道PHP是怎么实现在函数作用域找到全局变量的么?

  在我前面的文章中(深入理解PHP原理之Opcodes)讲过, PHP的执行,经历了如下几个阶段:

 

  1. Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)

  2. Parsing, 将Tokens转换成简单而有意义的表达式

  3. Compilation, 将表达式编译成Opocdes

  4. Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

 

  那么,第一阶段,自然就是Scanning了, 在词法分析阶段,我们的

 

  global $var;

 

  会被解析为:

 

  T_GLOBAL var;

 

  接下来是parsing阶段:

 

  T_GLOBAL var;

 

  yacc经过规则:

 

  statement:

  | T_GLOBAL global_var_list ';'

  ....

  global_var_list:

  global_var_list ',' global_var { zend_do_fetch_global_variable(&$3, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); }

  | global_var { zend_do_fetch_global_variable(&$1, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); }

  ;

 

  其中, zend_do_fetch_global_variable是真正生成opcode的函数:

 

  zend_op *opline;

  ......

  opline->opcode = ZEND_FETCH_W;

  opline->result.op_type = IS_VAR;

  ......

  opline->op2.u.EA.type = ZEND_FETCH_GLOBAL_LOCK;

 

  而对于ZEND_FETCH_W的op_handler是:

  ZEND_VM_HANDLER(83, ZEND_FETCH_W, CONST|TMP|VAR|CV, ANY) { ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_W); }

  我们来看看zend_fetch_var_adress_helper:

  ..... target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), type, varname TSRMLS_CC);/* if (!target_symbol_table) { ZEND_VM_NEXT_OPCODE(); }*/ if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() } }

  可以看出,核心就是zend_get_targer_symbol_table这个函数了:

  static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_variable *Ts, int type, zval *variable TSRMLS_DC){ switch (opline->op2.u.EA.type) { case ZEND_FETCH_LOCAL: return EG(active_symbol_table); break;

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号