PHP源碼分析之Global關鍵字

來源:互聯網
上載者:User

 

  閑來無事,就系統的從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, CONSTTMPVARCV, 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; case ZEND_FETCH_GLOBAL: case ZEND_FETCH_GLOBAL_LOCK: return &EG(symbol_table); break; case ZEND_FETCH_STATIC: if (!EG(active_op_array)->static_variables) { ALLOC_HASHTABLE(EG(active_op_array)->static_variables); zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); } return EG(active_op_array)->static_variables; break; EMPTY_SWITCH_DEFAULT_CASE() } return NULL;}

  恩,問題清楚了,也就是說, 如果你global了一個變數,那麼Zend就會去全域symbol_table去尋找,如果找不到,就會在全域symbol_table中分配相應的變數。

  通過這樣的機制,實現了全域變數。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.