#PHP扩展加载顺序
在PHP开发中使用扩展会大大提高编码和运行效率,但在使用过程中(尤其是一些开源扩展)难免遇到各种各样的问题,其中一个就是模块间冲突或依赖
一般来讲,比较好的扩展会提示你跟它冲突或有依赖的模块,运行php -m会有类似下面的这个提示
说明扩展testso所依赖的apm.so并没有被安装
如果我们继续深入了解这种功能如何实现的,那么就要研究一下该扩展的源码。其实做到这点并不复杂,也不需要太多的扩展开发知识,只需要了解几个结构体的相关功能即可
首先,每个扩展都会声明一个zend_module_entry结构的扩展说明模块,告诉Zend所有该模块相关信息。自然也包含所依赖和冲突的模块。当依赖关系出错的时候Zend就会报错,给出详细的出错信息,并停止运行
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;
const char *build_id;
};
deps就是用来注册依赖、冲突模块的,它的结构zend_module_dep如下:
struct _zend_module_dep {
const char *name; /* module name */
const char *rel; /* version relationship: NULL (exists), lt|le|eq|ge|gt (to given version) */
const char *version; /* version */
unsigned char type; /* dependency type */
};
我们可以通过研究代码及注释来了解这个结构体的使用方法,不过还有更好的方法,原来PHP贴心的提供了几个宏来完成zend_module_dep的填写:
ZEND_MOD_REQUIRED
ZEND_MOD_CONFLICTS
ZEND_MOD_OPTIONAL
比如在刚开始说到的testso中,我就是这么写的:
static const zend_module_dep test_deps[] = {
ZEND_MOD_REQUIRED("apm")
ZEND_MOD_END
};
zend_module_entry testso_module_entry = {
STANDARD_MODULE_HEADER_EX,
NULL,
test_deps, //zend_module_dep
"testso",
testso_functions,
PHP_MINIT(testso),
PHP_MSHUTDOWN(testso),
PHP_RINIT(testso),
PHP_RSHUTDOWN(testso),
PHP_MINFO(testso),
PHP_TESTSO_VERSION,
STANDARD_MODULE_PROPERTIES
};
至于第三个宏ZEND_MOD_OPTIONAL怎么用,大家有兴趣可以自行研究源码。在PHP这种开源项目中,源码本身就向你说明了一切
最后再讲一下扩展加载顺序的问题,这个规则更简单,只有一条:写在php.ini中的扩展按从上到下的顺序加载
比如在上面的情况中,testso的顺序就在apm之前。但是尽管放心,扩展依赖并不取决于加载顺序,所以把apm放在后面,PHP仍然可以正常执行