leevis.com icon indicating copy to clipboard operation
leevis.com copied to clipboard

php扩展开发

Open vislee opened this issue 7 years ago • 0 comments

概述

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

vislee avatar May 21 '18 09:05 vislee