- URL: https://www.laruence.com/en/2009/08/18/1042.html
- Please include attribution when republishing.
A reader, cyj, asked: if two PHP extension modules depend on each other, how do you guarantee the correct load order?
In other words, how do you enforce a module's dependency relationships?
On this question, we can start from the following two points:
1. An extension's load order is tied to the order in which it appears in the configuration file. That is, if the order in the configuration file is as follows,
extension=mysql.so
extension=pdo.so
then the mysql extension is loaded before the pdo extension.
Likewise, for separate configuration files, it depends on the load order of those files. Generally speaking, at that point it comes down to the file naming.
2. So if the order is wrong, how do we guarantee correct loading, or tell Zend that something went wrong?
Recall that when we write an extension, we always declare a zend_module_entry structure describing the extension. This structure tells Zend all the information about the current module that Zend cares about. It is right here that we can declare the modules our module depends on, so that when the dependency relationship is wrong, Zend reports an error, gives detailed error information, and stops execution.
struct _zend_module_entry {
unsigned short size;
unsigned int zend_api;
unsigned char zend_debug;
unsigned char zts;
struct _zend_ini_entry *ini_entry;
struct _zend_module_dep *deps; //key field
char *name;
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);
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;
};
The 5th field, zend_module_dep, is a pointer to an array of zend_module_dep structures, used to point out all the modules the current module depends on. The zend_module_dep structure is as follows:
struct _zend_module_dep {
char *name; /* module name */
char *rel; /* version relationship: NULL (exists), lt|le|eq|ge|gt (to given version) */
char *version; /* version */
unsigned char type; /* dependency type */
};
But, very much in PHP's style, we don't need to know the details of this structure, nor touch it directly. We can use the macro PHP provides — GET_MOD_REQUIRE — to fill in the zend_module_dep. For example, in pdo_mysql:
static zend_module_dep pdo_mysql_deps[] = {
ZEND_MOD_REQUIRED("pdo")
{NULL, NULL, NULL}
};
This declares that pdo_mysql must depend on the pdo extension module.
Then, fill this array pointer into the corresponding field of pdo_mysql_module_entry, and our goal is achieved.
Be First to Comment