[PHP kernel learning] Analysis of global keyword parsing process this article github address:
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
| = ----------------------------------------------------------------------- = |
| = -------------------- = [Analysis of the global keyword parsing process] = ------------------- = |
| = ----------------------------------------------------------------------- = |
| = ------------------------ = [By d4shman] = --------------------------- = |
| = ----------------------------------------------------------------------- = |
| = ------------------------- = [May 8, 2014] = --------------------------- = |
| = ----------------------------------------------------------------------- = |
[Directory]
0x01 lexical analysis
0X02 syntax analysis
0X03 explain execution
0X04 references
0x01 lexical analysis
D4shman @ gentoo # vi/php-dev/php-5.4.8/Zend/zend_language_scanner.l
Find global:
"Global "{
Return T_GLOBAl;
}
Returns a token T_GLOBAL.
0X02 syntax analysis
Use token T_GLOBAL to find zend_language_parser.y:
| 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 );}
;
The above $3 refers to global_val. we can see that for global variables, the syntax analyzer calls the Zend Engine.
Zend_do_fetch_globa_variable function. This function is declared in Zend/zend_compile.c
0X03 explain execution
Find the zend_do_fetch_global_variable function definition in Zend/zend_compile.c:
Void zend_do_fetch_global_variable (znode * varname, const znode * static_assignment, int fetch_type TSRMLS_DC)
{
Zend_op * opline;
Znode lval;
Znode result;
/* If the variable type is constant and not a string, convert it to the string type */
If (varname-> op_type = IS_CONST ){
If (Z_TYPE (varname-> u. constant )! = IS_STRING ){
Convert_to_string (& varname-> u. constant );
}
}
Opline = get_next_op (CG (active_op_array) TSRMLS_CC);/* CG: compile_global */
Opline-> opcode = ZEND_FETCH_W;/* the default mode must be Write */
Opline-> result_type = IS_VAR;
Opline-> result. var = get_temporary_variable (CG (active_op_array ));
SET_NODE (opline-> op1, varname );
If (opline-> op1_type = IS_CONST ){
CALCULATE_LITERAL_HASH (opline-> op1.constant );
}
SET_UNUSED (opline-> op2 );
Opline-> extended_value = fetch_type;
GET_NODE (& result, opline-> result );
If (varname-> op_type = IS_CONST ){
Zval_copy_ctor (& varname-> u. constant );
}
/* Relies on the fact that the default fetch is BP_VAR_W */
Fetch_simple_variable (& lval, varname, 0 TSRMLS_CC );
Zend_do_assign_ref (NULL, & lval, & result TSRMLS_CC );
CG (active_op_array)-> opcodes [CG (active_op_array)-> last-1]. result_type | = EXT_TYPE_UNUSED;
}
The code above confirms that the opcode is ZEND_FETCH_W, and the zend_do_assign_ref function is also executed. Zend_do_assign_ref function
There is such a key statement:
Opline-> opcode = ZEND_ASSIGN_REF;
Therefore, two Opcodes: ZEND_FETCH_W and ZEND_ASSIGN_REF are actually executed during the syntax analysis.
The corresponding opcode is 83 and 39, respectively. The final call method for computing is (defined in zend_execute.c :):
Zend_opcode_handlers [opcode * 25 + zend_vm_decode [op-> op1.op _ type] * 5 + zend_vm_decode [op-> op2.op _ type];
After calculation (// I have not figured out how to calculate it //), the called function is:
Static int ZEND_FASTCALL ZEND_FETCH_W_SPEC_CV_HANDLER (ZEND_OPCODE_HANDLER_ARGS)
{
Return zend_fetch_var_address_helper_SPEC_CV (BP_VAR_W, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU );
}
In zend_fetch_var_address_helper_SPEC_CV, call the following code to obtain the symbol table:
Target_symbol_table = zend_get_target_symbol_table (opline, EX (Ts), type, varname TSRMLS_CC );
The implementation of the zend_get_target_symbol_table function is as follows (in ):
Static inline HashTable * zend_get_target_symbol_table (int fetch_type TSRMLS_DC)
{
Switch (fetch_type ){
Case ZEND_FETCH_LOCAL:
If (! EG (active_symbol_table )){
Zend_rebuild_symbol_table (TSRMLS_C );
}
Return EG (active_symbol_table );
Break;
Case ZEND_FETCH_GLOBAL:
Case ZEND_FETCH_GLOBAL_LOCK:
Return & EG (symbol_table);/* return the address of the global variable 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;
}
The code shows that when the passed fetch_type is ZEND_FETCH_GLOBAL (_ LOCK), the function uses the macro of EG (excutor_global ).
Returns the symbol table address of the global variable.
The above is the whole process of global variable parsing and execution.
0X04 references
Deep understanding of PHP kernel