The zend_module structure

The main source file of a PHP extension contains several new constructs for a C programmer. The most important of these, the one touched first when starting a new extension, is the zend_module structure. This structure contains a wealth of information that tells the Zend Engine about the extension's dependencies, version, callbacks, and other critical data. The structure has mutated considerably over time; this section will focus on the structure as it has appeared since PHP 5.2, and will identify the very few parts which have changed in PHP 5.3.

The zend_module declaration from counter.c looks like this before any code has been written. The example file was generated by ext_skel --extname=counter, with some obsolete constructs removed:

Example #1 zend_module declaration in the counter extension

/* {{{ counter_module_entry
 */
zend_module_entry counter_module_entry = {
    STANDARD_MODULE_HEADER,
    "counter",
    counter_functions,
    PHP_MINIT(counter),
    PHP_MSHUTDOWN(counter),
    PHP_RINIT(counter),        /* Replace with NULL if there's nothing to do at request start */
    PHP_RSHUTDOWN(counter),    /* Replace with NULL if there's nothing to do at request end */
    PHP_MINFO(counter),
    "0.1", /* Replace with version number for your extension */
    STANDARD_MODULE_PROPERTIES
};
/* }}} */

This may look a bit daunting at first glance, but most of it is very simple to understand. Here's the declaration of zend_module from zend_modules.h in PHP 5.3:

Example #2 zend_module definition in PHP 5.3

struct _zend_module_entry {
    unsigned short size;
    unsigned int zend_api;
    unsigned char zend_debug;
    unsigned char zts;
    const struct _zend_ini_entry *ini_entry;
    const struct _zend_module_dep *deps;
    const char *name;
    const struct _zend_function_entry *functions;
    int (*module_startup_func)(INIT_FUNC_ARGS);
    int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
    int (*request_startup_func)(INIT_FUNC_ARGS);
    int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
    void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
    const char *version;
    size_t globals_size;
#ifdef ZTS
    ts_rsrc_id* globals_id_ptr;
#else
    void* globals_ptr;
#endif
    void (*globals_ctor)(void *global TSRMLS_DC);
    void (*globals_dtor)(void *global TSRMLS_DC);
    int (*post_deactivate_func)(void);
    int module_started;
    unsigned char type;
    void *handle;
    int module_number;
};

Many of these fields will never be touched by an extension writer. There are a number of standard macros that set them to their proper values automatically. The macro STANDARD_MODULE_HEADER fills in everything up to the deps field. Alternatively, the STANDARD_MODULE_HEADER_EX will leave the deps field empty for the developer's use. The developer is always responsible for everything from name to version. After that, the STANDARD_MODULE_PROPERTIES macro will fill in the rest of the structure, or the STANDARD_MODULE_PROPERTIES_EX macro can be used to leave the extension globals and post-deactivation function fields unfilled. Most modern extensions will make use of module globals.

Notă:

This table gives the values that each field would have if the developer were to fill in the structure entirely by hand, without recourse to any of the shortcut macros. This is not recommended. The "correct" values for many fields may change. Use the macros whenever possible.

Module structure field values
Field Value Description
size [1] [2] [3] sizeof(zend_module_entry) The size in bytes of the structure.
zend_api [1] [2] [3] ZEND_MODULE_API_NO The version of the Zend API this module was compiled against.
zend_debug [1] [2] [3] ZEND_DEBUG A flag indicating whether the module was compiled with debugging turned on.
zts [1] [2] [3] USING_ZTS A flag indicating whether the module was compiled with ZTS (TSRM) enabled (see Memory management).
ini_entry [1] [3] NULL This pointer is used internally by Zend to keep a non-local reference to any INI entries declared for the module.
deps [3] NULL A pointer to a list of dependencies for the module.
name "mymodule" The name of the module. This is the short name, such as "spl" or "standard".
functions mymodule_functions A pointer to the module's function table, which Zend uses to expose functions in the module to user space.
module_startup_func PHP_MINIT(mymodule) A callback function that Zend will call the first time a module is loaded into a particular instance of PHP.
module_shutdown_func PHP_MSHUTDOWN(mymodule) A callback function that Zend will call the when a module is unloaded from a particular instance of PHP, typically during final shutdown.
request_startup_func PHP_RINIT(mymodule) A callback function that Zend will call at the beginning of each request. This should be as short as possible or NULL as calling this has costs on every request.
request_shutdown_func PHP_RSHUTDOWN(mymodule) A callback function that Zend will call at the end of each request. This should be as short as possible or NULL as calling this has costs on every request.
info_func PHP_MINFO(mymodule) A callback function that Zend will call when the phpinfo() function is called.
version NO_VERSION_YET A string giving the version of the module, as specified by the module developer. It is recommended that the version number be either in the format expected by version_compare() (e.g. "1.0.5-dev"), or a CVS or SVN revision number (e.g. "$Rev: 322138 $").
globals_size [1] [4] [5] [6] sizeof(zend_mymodule_globals) The size of the data structure containing the module's globals, if any.
globals_id_ptr [1] [4] [5] [6] [7] &mymodule_globals_id Only one of these two fields will exist, depending upon whether the USING_ZTS constant is TRUE. The former is an index into TSRM's allocation table for the module's globals, and the latter is a pointer directly to the globals.
globals_ptr [1] [4] [5] [6] [8] &mymodule_globals
globals_ctor [4] [5] [6] PHP_GINIT(mymodule) This funtion is called to initialize a module's globals before any module_startup_func.
globals_dtor [4] [5] [6] PHP_GSHUTDOWN(mymodule) This funtion is called to deallocate a module's globals after any module_shutdown_func.
post_deactivate_func [4] ZEND_MODULE_POST_ZEND_DEACTIVATE_N(mymodule) This function is called by Zend after request shutdown. It is rarely used.
module_started [1] [9] [4] 0 These fields are used for Zend's internal tracking information.
type [1] [9] [4] 0
handle [1] [9] [4] NULL
module_number [1] [9] [4] 0
[1] This field is not intended for use by module developers.
[2] This field is filled in by STANDARD_MODULE_HEADER_EX.
[3] This field is filled in by STANDARD_MODULE_HEADER.
[4] This field is filled in by STANDARD_MODULE_PROPERTIES.
[5] This field is filled in by NO_MODULE_GLOBALS.
[6] This field is filled in by PHP_MODULE_GLOBALS.
[7] This field only exists when USING_ZTS is TRUE.
[8] This field only exists when USING_ZTS is FALSE.
[9] This field is filled in by STANDARD_MODULE_PROPERTIES_EX.

Filling in the structure in a practical situation

With all these fields to play with, it can be confusing to know which to use for what purpose. Here is the zend_module definition from the "counter" example extension after updating it to its final form.

Example #3 Counter extension module definition

/* {{{ counter_module_entry
 */
zend_module_entry counter_module_entry = {
    STANDARD_MODULE_HEADER,
    "counter",
    counter_functions,
    PHP_MINIT(counter),
    PHP_MSHUTDOWN(counter),
    PHP_RINIT(counter),
    PHP_RSHUTDOWN(counter),
    PHP_MINFO(counter),
    NO_VERSION_YET,
    PHP_MODULE_GLOBALS(counter),
    PHP_GINIT(counter),
    PHP_GSHUTDOWN(counter),
    NULL,
    STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
  • STANDARD_MODULE_HEADER is used since this module doesn't define any dependencies.
  • "counter" is the extension's name, and is used to define the various callback functions the module passes to Zend. "counter" uses module, globals, and request functions at startup and shutdown times, and provides information to phpinfo(), so all seven callbacks are defined.
  • It is assumed that there is a variable of type zend_function_entry * named counter_functions earlier in the file that contains the module definition, listing the functions the module exports to userspace.
  • NO_VERSION_YET is a particularly nice way of telling Zend the module doesn't have a version. It might have been more correct to place "1.0" here instead in a real module.
  • "counter" uses per-module globals, so PHP_MODULE_GLOBALS is used
  • This module has no post-deactivate function, so NULL is used.
  • Since this module does use globals, STANDARD_MODULE_PROPERTIES_EX is used to finish the structure.

What's changed between 5.2 and 5.3?

Nothing. The only differences in the zend_module structure between PHP 5.2 and PHP 5.3 are a few const keywords.