Global Variables in PHP 7 Internals

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.

Tags: PHP PHP Internals Global Variables Zend Engine Symbol Table

Posted on Fri, 15 May 2026 22:31:09 +0000 by mcovalt