Free to do nothing, on the system from the lexical analysis of PHP, syntax analysis, opcodes generation, implementation, the entire process, detailed analysis of the Global keyword implementation.
When you write in the script:
<?php
$var = "Laruence";
Function sample () {
Global $var;
}
?>
, do you know how PHP implements the global variables found in the scope of the function?
In my previous article (a deep understanding of the PHP principles of opcodes), PHP's implementation has gone through several stages:
1. Scanning (lexing), convert the PHP code into a language fragment (tokens)
2. Parsing, converts tokens into simple and meaningful expressions
3. Compilation, compile the expression into Opocdes
4. Execution, execute opcodes in sequence, one at a time, so as to realize the function of PHP script.
So, the first stage, nature is scanning, in the lexical analysis stage, our
Global $var;
will be resolved to:
T_global var;
Next is the parsing phase:
T_global var;
YACC after the 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);}
;
Where zend_do_fetch_global_variable is the function that really 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;
And the Op_handler for Zend_fetch_w is:
Zend_vm_handler (Zend_fetch_w, CONSTTMPVARCV, 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_st Rval_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 * * 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 ()}}
As you can see, the core is zend_get_targer_symbol_table this function:
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); 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); 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;}
Well, the question is clear, that is to say, if you have a variable global, then Zend will go to the global symbol_table to find, if not found, will be in the global symbol_table allocation of the corresponding variables.
With such a mechanism, global variables are implemented.