A more accessible place to expose information to the scripts using your extension is to define constants that can be accessed by scripts at runtime, possibly allowing them to modify their behavior. In userspace, you'd declare a constant using the define() function; in internals, it's very nearly the same and uses the REGISTER_*_CONSTANT() family of macros.
Most constants are ones you'll want to make available in all scripts initialized to the same value. To declare these constants you'll declare them in the MINIT method:
PHP_MINIT_FUNCTION(sample4) { REGISTER_STRING_CONSTANT("SAMPLE4_VERSION", PHP_SAMPLE4_EXTVER, CONST_CS | CONST_PERSISTENT); return SUCCESS; }
The first parameter to this macro is the name of the constant as it will be exported to userspace. In this example, a userspace script will be able to issue echo SAMPLE4_VERSION; and have 1.0 output. It's important to note here that the REGISTER_*_CONSTANT() family of macros use a call to sizeof() to determine the constant name's length. This means that only literal values may be used. Attempting to use a char* variable will result in an incorrect string length of sizeof(char*)usually 4 on 32-bit platforms.
Next comes the constant's value itself. In most cases this is a single parameter of the named type; however, the STRINGL version you'll see in a moment does require a second length parameter. When registering string constants, the string value is not copied into the constant, but merely referenced by it. This means that dynamically created strings need to be allocated in permanent memory and freed during the appropriate shutdown phase.
Finally, in the last parameter you'll pass a bitwise OR combination of two optional flags. Including the CONST_CS flag will specify the constant as being case-sensitive. This is the default for user-defined constants and nearly all the internal constants used by PHP as well. For a few special cases, such as trUE, FALSE, and NULL, this parameter is omitted enabling them to be resolved in a noncase-sensitive manner.
The second of the two flags for constant registration is the persistency flag. When declaring constants in MINIT, they must be built to persist from request to request. When declared within a request, such as during RINIT, you mayand almost always shouldomit this flag, allowing the engine to destroy the constant at the end of the request.
The following prototypes describe the four available constant registration macros. Remember that the name parameter must be a string literal and not a char* variable.
REGISTER_LONG_CONSTANT(char *name, long lval, int flags) REGISTER_DOUBLE_CONSTANT(char *name, double dval, int flags) REGISTER_STRING_CONSTANT(char *name, char *value, int flags) REGISTER_STRINGL_CONSTANT(char *name, char *value, int value_len, int flags)
If the string must be initialized from a variable name, such as within a loop, you can use the underlying function calls to which these macros map:
void zend_register_long_constant(char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC) void zend_register_double_constant(char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC) void zend_register_string_constant(char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC) void zend_register_stringl_constant(char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC)
This time, the length of the name parameter can be supplied directly by the calling scope. You'll notice this time that TSRMLS_CC must be explicitly passed and that a new parameter has been introduced.
module_number is assigned by the engine when your extension is loaded and serves as a clue during module cleanup as your extension is unloaded. You don't need to worry about what the value of this variable is; just pass it. It's supplied in the prototype for all MINIT and RINIT methods, and is therefore available when you declare your constants. Here's the same constant registration again:
PHP_MINIT_FUNCTION(sample4) { register_string_constant("SAMPLE4_VERSION", sizeof("SAMPLE4_VERSION"), PHP_SAMPLE4_EXTVER, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC); return SUCCESS; }
Notice again that when sizeof() was used to determine the length of SAMPLE4_VERSION, it was not reduced by one. Constant's names are expected to include their terminating NULL. If you're starting with a strlen() determined length, be sure to add one to it so that the terminating NULL is included as well.
With the exception of arrays and objects, the remaining types can also be registered, but because no macros or functions exist in the Zend API to cover these types, you'll have to manually declare the constants. To do this, follow this simple recipe, substituting the appropriate type when you create the zval*:
void php_sample4_register_boolean_constant(char *name, uint len, zend_bool bval, int flags, int module_number TSRMLS_DC) { zend_constant c; ZVAL_BOOL(&c.value, bval); c.flags = CONST_CS | CONST_PERSISTENT; c.name = zend_strndup(name, len - 1); c.name_len = len; c.module_number = module_number; zend_register_constant(&c TSRMLS_CC); }
Extension Globals |
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