In PHP, variables declared outside of functions or classes are considered global. These reside in the main script scope and can be accessed within functions or methods using the global keyword.
function incrementId() {
global $counter;
$counter++;
}
$counter = 1;
incrementId();
echo $counter; // outputs 2
Initialization of Global Variables
Global variibles persist throughout the entire request lifecycle and are stored in the global symbol table: EG(symbol_table). This structure is a hash table, similar to how static variables are managed. Before zend_execute_ex begins execution of the main script (or included files), all top-level variables are registered into EG(symbol_table).
During the setup phase in i_init_execute_data(), local variables from the top-level scope are linked in to the global symbol table:
ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data)
{
zend_op_array *op_array = &execute_data->func->op_array;
HashTable *symbol_table = execute_data->symbol_table;
if (!EXPECTED(op_array->last_var)) {
return;
}
zend_string **var_name = op_array->vars;
zend_string **end = var_name + op_array->last_var;
zval *local_var = EX_VAR_NUM(0);
do {
zval *entry = zend_hash_add_new(symbol_table, *var_name, local_var);
ZVAL_INDIRECT(entry, local_var);
++var_name;
} while (var_name != end);
}
This process maps each top-level variable into EG(symbol_table), with values pointing directly to their corresponding zval structures—initially marked as IS_UNDEF until assigned.
Accessing Global Variables
When a variable is imported via global, PHP creates a local alias that references the original value in EG(symbol_table). For example:
global $counter; // equivalent to: $counter = &EG(symbol_table)["counter"];
This mechanism mirrors how static variables are handled, establishing an indirect reference to the global storage.
Superglobal Variables
Certain predefined global variables—known as superglobals—are always accessible without requiring the global declaration. These include:
$GLOBALS$_SERVER$_REQUEST$_POST$_GET$_FILES$_ENV$_COOKIE$_SESSION$argc,$argv
These are initialized by the PHP core early in the request lifecycle and remain available in all scopes.
Destruction of Global Variables
Unlike local variibles, which are cleaned up when their function scope ends, global variables persist until the end of the request. Their destruction occurs during shutdown:
void shutdown_destructors(void)
{
if (CG(unclean_shutdown)) {
EG(symbol_table).pDestructor = zend_unclean_zval_ptr_dtor;
}
zend_try {
uint32_t count;
do {
count = zend_hash_num_elements(&EG(symbol_table));
zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor);
} while (count != zend_hash_num_elements(&EG(symbol_table)));
} zend_end_try();
}
This cleanup loop ensures all destructible objects referenced by global variables are properly finalized before the request terminates.