php扩展开发
概述
php 有很多功能都是通过扩展实现的。自己也可以按照php提供的接口实现自己的模块。 也可以通过php-src目录下的ext/ext_skel 生成一个扩展所需要的框架。
扩展接口
生成扩展模块框架
例子: https://github.com/php/php-src/blob/master/ext/zend_test/test.c
接口
/*******************************
* zend_modules.h
*/
// 扩展模块结构体定义
// typedef struct _zend_module_entry zend_module_entry;
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;
// 上述结构体通常用STANDARD_MODULE_HEADER 填充
const char *name; // 模块名称
const struct _zend_function_entry *functions; // 定义了一些列函数,_zend_function_entry类型的数组
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); // 调用phpinfo()时打印扩展信息
const char *version;
// 下面的变量通常用STANDARD_MODULE_PROPERTIES填充
size_t globals_size;
#ifdef ZTS
ts_rsrc_id* globals_id_ptr;
#else
void* globals_ptr;
#endif
void (*globals_ctor)(void *global);
void (*globals_dtor)(void *global);
int (*post_deactivate_func)(void);
int module_started;
unsigned char type;
void *handle;
int module_number;
const char *build_id;
};
/*******************************
* zend_API.h
*/
// 该文件中定义了大量的宏
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags },
#define ZEND_FN(name) zif_##name
#define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define INIT_CLASS_ENTRY(class_container, class_name, functions) \
INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, NULL, NULL, NULL)
typedef struct _zend_function_entry {
const char *fname; // 函数名称
void (*handler)(INTERNAL_FUNCTION_PARAMETERS); // 函数指针
const struct _zend_internal_arg_info *arg_info; // zend内部的变量
uint32_t num_args;
uint32_t flags;
} zend_function_entry;
/*******************************
* zend_compile.h
*/
/* arg_info for internal functions */
typedef struct _zend_internal_arg_info {
const char *name;
const char *class_name;
zend_uchar type_hint;
zend_uchar pass_by_reference;
zend_bool allow_null;
zend_bool is_variadic;
} zend_internal_arg_info;
/*******************************
* zend.h
*/
struct _zend_class_entry {
char type;
zend_string *name;
struct _zend_class_entry *parent;
int refcount;
uint32_t ce_flags;
int default_properties_count;
int default_static_members_count;
zval *default_properties_table;
zval *default_static_members_table;
zval *static_members_table;
HashTable function_table;
HashTable properties_info;
HashTable constants_table;
union _zend_function *constructor;
union _zend_function *destructor;
union _zend_function *clone;
union _zend_function *__get;
union _zend_function *__set;
union _zend_function *__unset;
union _zend_function *__isset;
union _zend_function *__call;
union _zend_function *__callstatic;
union _zend_function *__tostring;
union _zend_function *__debugInfo;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
zend_class_iterator_funcs iterator_funcs;
/* handlers */
zend_object* (*create_object)(zend_class_entry *class_type);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref);
int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type); /* a class implements this interface */
union _zend_function *(*get_static_method)(zend_class_entry *ce, zend_string* method);
/* serializer callbacks */
int (*serialize)(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data);
int (*unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data);
uint32_t num_interfaces;
uint32_t num_traits;
zend_class_entry **interfaces;
zend_class_entry **traits;
zend_trait_alias **trait_aliases;
zend_trait_precedence **trait_precedences;
union {
struct {
zend_string *filename;
uint32_t line_start;
uint32_t line_end;
zend_string *doc_comment;
} user;
struct {
const struct _zend_function_entry *builtin_functions;
struct _zend_module_entry *module;
} internal;
} info;
};
/*******************************
* zend_ini.h
*/
typedef struct _zend_ini_entry_def {
const char *name;
ZEND_INI_MH((*on_modify));
void *mh_arg1;
void *mh_arg2;
void *mh_arg3;
const char *value;
void (*displayer)(zend_ini_entry *ini_entry, int type);
int modifiable;
uint name_length;
uint value_length;
} zend_ini_entry_def;
#define ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, arg1, arg2, arg3, displayer) \
{ name, on_modify, arg1, arg2, arg3, default_value, displayer, modifiable, sizeof(name)-1, sizeof(default_value)-1 },
#define ZEND_INI_ENTRY_EX(name, default_value, modifiable, on_modify, displayer) \
ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, NULL, NULL, NULL, displayer)
#define ZEND_INI_ENTRY(name, default_value, modifiable, on_modify) \
ZEND_INI_ENTRY_EX(name, default_value, modifiable, on_modify, NULL)
// #define PHP_INI_BEGIN ZEND_INI_BEGIN
#define ZEND_INI_BEGIN() static const zend_ini_entry_def ini_entries[] = {
// #define PHP_INI_END ZEND_INI_END
#define ZEND_INI_END() { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0} };
// zend_register_ini_entries 实现在zend_ini.c文件中,把解析配置的结构体添加到zend框架中。
#define REGISTER_INI_ENTRIES() zend_register_ini_entries(ini_entries, module_number)
// zend_ini_string_ex 实现在zend_ini.c文件中,获取配置文件该配置的值
#define INI_STR(name) zend_ini_string_ex((name), sizeof(name)-1, 0, NULL)
-
functions 的实现参考例子中zend_test_functions数组 数组中元素的添加通过宏PHP_FE,宏的定义查看上述代码。 函数的变量定义,首先函数的变量类型是_zend_internal_arg_info,参考上述结构体。php源码提供了很多宏实现函数变量结构体。 函数的实现需要用到ZEND_FUNCTION宏,该宏的定义参考上述代码。 函数实现中变量的获取用到 zend_parse_parameters函数,具体实现在zend_API.c文件中。
-
module_startup_func 函数通常用来解析配置文件,或者初始化zend_class_entry的一个变量(见上述定义),定义PHP_MINIT(zend_test) PHP_MINIT_FUNCTION(zend_test)实现, 实现和定义用的宏不一样。用INIT_CLASS_ENTRY宏初始化一个zend_class_entry类型的结构体,zend_register_internal_interface函数申请一个zend_class_entry类型的结构体并用INIT_CLASS_ENTRY宏初始化的结构体赋值后返回。 php源码也定义了一些宏来支持配置的定义和解析,见zend_ini.h文件。
总结
[参考] https://github.com/php/php-src/blob/master/ext/zend_test/test.c http://www.cnblogs.com/lchb/articles/2801392.html http://yangxikun.com/php/2016/07/10/php-zend-extension.html http://php.net/manual/zh/internals2.structure.modstruct.php