You've used PHP from the userspace side of things, so you're already familiar with the concept of an array. Any number of PHP variables (zvals) can be dropped into a single container (array) and be given names (labels) in the form of numbers or strings.
What's hopefully not surprising is that every single variable in a PHP script can be found in an array. When you create a variable, by assigning a value to it, Zend stores that value into an internal array known as a symbol table.
One symbol table, the one that defines the global scope, is initialized upon request startup just before extension RINIT methods are called, and then destroyed after script completion and subsequent RSHUTDOWN methods have executed.
When a userspace function or object method is called, a new symbol table is allocated for the life of that function or method and is defined as the active symbol table. If current script execution is not in a function or method, the global symbol table is considered active.
Taking a look at the execution globals structure (defined in Zend/zend_globals.h), you'll find the following two elements defined:
struct _zend_execution_globals { ... HashTable symbol_table; HashTable *active_symbol_table; ... };
The symbol_table, accessed as EG(symbol_table), is always the global variable scope much like the $GLOBALS variable in userspace always corresponds to the global scope for PHP scripts. In fact, the $GLOBALS variable is just a userspace wrapper around the EG(symbol_table) variable seen from the internals.
The other part of this pair, active_symbol_table, is similarly accessed as EG(active_symbol_table), and represents whatever variable scope is active at the time.
The key difference to notice here is that EG(symbol_table), unlike nearly every other HashTable you'll use and encounter while working with the PHP and Zend APIs, is a direct variable. Nearly all functions that operate on HashTables, however, expect an indirect HashTable* as their parameter. Therefore, you'll have to dereference EG(symbol_table) with an ampersand when using it.
Consider the following two code blocks, which are functionally identical:
In PHP:
In C:
{ zval *fooval; MAKE_STD_ZVAL(fooval); ZVAL_STRING(fooval, "bar", 1); ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", fooval); }
First, a new zval was allocated using MAKE_STD_ZVAL() and its value was initialized to the string "bar". Then a new macro, which roughly equates with the assignment operator (=), combines that value with a label (foo), and adds it to the active symbol table. Because no userspace function is active at the time, EG(active_symbol_table) == &EG(symbol_table), which ultimately means that this variable is stored in the global scope.
The PHP Life Cycle
Variables from the Inside Out
Memory Management
Setting Up a Build Environment
Your First Extension
Returning Values
Accepting Parameters
Working with Arrays and HashTables
The Resource Data Type
PHP4 Objects
PHP5 Objects
Startup, Shutdown, and a Few Points in Between
INI Settings
Accessing Streams
Implementing Streams
Diverting the Stream
Configuration and Linking
Extension Generators
Setting Up a Host Environment
Advanced Embedding
Appendix A. A Zend API Reference
Appendix B. PHPAPI
Appendix C. Extending and Embedding Cookbook
Appendix D. Additional Resources