As we saw in the previous section, the symbol_table and active_symbol_table hashes contain user-accessible variables. You can inject new variables or change existing ones in these hashes.
Here is a trivial function that, when called, creates $foo with a value of 99 in the currently active symbol table:
PHP_FUNCTION(foo) { zval *var; MAKE_STD_ZVAL(var); Z_LVAL_P(var)=99; Z_TYPE_P(var)=IS_LONG; ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", var); }
That means that if this function was called from within a user-space function, the variable would be injected into the function-local symbol table. If this function was called from the global scope, the variable would, of course, be injected into the global symbol table. To inject the variable directly into the global symbol table regardless of the current scope, simply use EG(symbol_table) instead of EG(active_symbol_table). Note that the global symbol table is not a pointer.
Here we also see an example of manually setting the type of a container and filling in the corresponding long value. The valid container-type constants are:
#define IS_NULL 0 #define IS_LONG 1 #define IS_DOUBLE 2 #define IS_STRING 3 #define IS_ARRAY 4 #define IS_OBJECT 5 #define IS_BOOL 6 #define IS_RESOURCE 7 #define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9
The ZEND_SET_SYMBOL( ) macro is somewhat complex. It first checks to see if the symbol you are setting is already there and if that symbol is a reference. If so, the existing container is reused and simply pointed at the new data you have provided. If the symbol does not already exist, or it exists and it isn't a reference, zend_hash_update( ) is called. zend_hash_update( ) directly overwrites and frees the existing value. You can call zend_hash_update( ) directly yourself if you want to and if you are more worried about performance than memory conservation. This is similar to the previous example, except that we force an overwrite in the symbol table using zend_hash_update( ):
PHP_FUNCTION(foo) { zval *var; MAKE_STD_ZVAL(var); Z_LVAL_P(var)=99; Z_TYPE_P(var)=IS_LONG; zend_hash_update(&EG(symbol_table), "foo", sizeof("foo"), &var, sizeof(zval *), NULL); }
The arguments to zend_hash_update( ) should be self-explanatory, except for that final NULL. To get back the address of the new container, pass a void ** instead of NULL; the void * whose address you pass will be set to the address of the new container. Typically, this last argument is always NULL.
Copyright © 2003 O'Reilly & Associates. All rights reserved.