The system analyzes the implementation of global keywords in detail from the lexical analysis, syntax analysis, opcodes generation, execution, and whole process of PHP. When you write in the script: & lt ;? Php $ var = & quot; laruence & quot; functionsample () {globa... "> <LINKhref =" h
The system analyzes the implementation of global keywords in detail from the lexical analysis, syntax analysis, opcodes generation, execution, and whole process of PHP.
When you write in the script:
$ Var = "laruence ";
Function sample (){
Global $ var;
}
?>
Do you know how PHP can find global variables in the function scope?
As mentioned in my previous article (Opcodes, a deep understanding of PHP principles), PHP execution has gone through the following stages:
1. Scanning (Lexing) converts PHP code into a language snippet (Tokens)
2. Parsing: converts Tokens into a simple and meaningful expression.
3. Compilation: compile the expression into Opocdes
4. Execution: execute Opcodes one by one at a time to implement the PHP script function.
The first stage is Scanning. in the lexical analysis stage, our
Global $ var;
Will be parsed:
T_GLOBAL var;
Next is the parsing phase:
T_GLOBAL var;
Yacc rules:
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 is the function that actually generates opcode:
Zend_op * opline;
......
Opline-> opcode = ZEND_FETCH_W;
Opline-> result. op_type = IS_VAR;
......
Opline-> op2.u. EA. type = ZEND_FETCH_GLOBAL_LOCK;
The op_handler of ZEND_FETCH_W is:
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 );}
Let's take a look at 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 (bytes); 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 ()}}
We can see that the core function is 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 when: return & EG (symbol_table); break; case ZEND_FETCH_STATIC: if (! EG (active_op_array)-> static_variables) {ALLOC_HASHTABLE (EG (active_op_array)-> static_variables); values (EG (active_op_array)-> static_variables, 2, NULL, values, 0 );} return EG (active_op_array)-> static_variables; break; EMPTY_SWITCH_DEFAULT_CASE ()} return NULL ;}
Well, the problem is clear. that is to say, if you have a global variable, Zend will go to the global symbol_table to find the variable. if you cannot find the variable, it will be allocated to the global symbol_table.
This mechanism is used to implement global variables.