原文:http://www.imsiren.com/archives/547
一个简单的扩展模块
PHP非常容易扩展,因为它提供了我们想用的所有API.
如果要新建一个扩展,需要在PHP源码中执行ext_skel
位置 PHP源码目录/ext/ext_skel
它有几个参数
–extname=module module is the name of your extension
–proto=file file contains prototypes of functions to create
–stubs=file generate only function stubs in file
–xml generate xml documentation to be added to phpdoc-cvs
–skel=dir path to the skeleton directory
–full-xml generate xml documentation for a self-contained extension
(not yet implemented)
–no-help don’t try to be nice and create comments in the code
and helper functions to test if the module compiled
如果我们要建一个 扩展名称为siren的模块,那么我们只要执行
ext_skel –extname=siren 它就会在 ext/目录下生成以 模块名称为名的文件夹.而且还会创建一些文件:
config.m4 config.w32 CREDITS EXPERIMENTAL php_siren.h siren.c siren.php tests
config.m4 和config.w32是我们的配置文件,我是在linux下编译的 所以要修改config.m4文件 两种加载方式 with 和 enable
1
2
3
4
5
6
7
8
9
|
dnl PHP_ARG_WITH(siren, for siren support,
dnl Make sure that the comment is aligned:
dnl [? --with-siren???????????? Include siren support])
?
dnl Otherwise use enable:
?
dnl PHP_ARG_ENABLE(siren,whether to enable siren support,
dnl Make sure that the comment is aligned:
dnl [? --enable-siren?????????? Enable siren support])
|
enable方式 需要重新编译PHP,这样是非常浪费时间的,所以我把它编译为so模块..
所以就用 with啦
dnl PHP_ARG_WITH(siren,for siren support,
dnl Make sure that the comment is aligned:
dnl [ --with-siren Include siren support])
为
PHP_ARG_WITH(siren,
Make sure that the comment is aligned:
[ --with-siren Include siren support])
这样在编译PHP的时候 –with-siren就可以加载此模块,也可以在php.ini中extension 模块.
在ext/siren目录下有一个siren.c文件
它提供了一个默认函数
1
2
3
4
5
6
7
8
9
10
11
12
13
|
PHP_FUNCTION(confirm_siren_compiled)
{
???????? char *arg = NULL;
???????? int arg_len,len;
???????? char *strg;
?
???????? if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s" ,&arg,&arg_len) == FAILURE) {
???????????????? return ;
???????? }??
?
???????? len = spprintf(&strg, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP." , "siren" ,arg);
???????? RETURN_STRINGL(strg,len,0);
}
|
如果看过 我之前的文章,你肯定明白 如果不知道 那就看看这篇文章 http://imsiren.com/archives/196 下面看看如何编译到PHP
1. /usr/local/php53/bin/phpize
2../configure –with-php-config=/usr/local/php53/bin/php-config
3.make && make install
这样 就会在/usr/local/php53/lib/php/extensions/no-debug-non-zts-20090626/目录下生成一个siren.so文件
这样 一个简单的扩展模块就完成了..我们在PHP.INI里面开启此模块
重启apache/nginx,这样 在php文件里 就可以 执行 confirm_siren_compiled函数了.
下面我们就详细讲解一下里面的东西
首先是 php_siren.h
它是siren.c加载的头文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#ifndef PHP_SIREN_H
#define PHP_SIREN_H
?
extern zend_module_entry siren_module_entry;
#define phpext_siren_ptr &siren_module_entry
?
#ifdef PHP_WIN32
#?????? define PHP_SIREN_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#?????? define PHP_SIREN_API __attribute__ ((visibility("default")))
#else
#?????? define PHP_SIREN_API
#endif
?
#ifdef ZTS
#include "TSRM.h"
#endif
?
PHP_MINIT_FUNCTION(siren);
PHP_MSHUTDOWN_FUNCTION(siren);
PHP_RINIT_FUNCTION(siren);
PHP_RSHUTDOWN_FUNCTION(siren);
PHP_MINFO_FUNCTION(siren);
?
PHP_FUNCTION(confirm_siren_compiled);??
?
?
????????
????????
?
???
???
???
???
???
???
???
?
#ifdef ZTS
#define SIREN_G(v) TSRMG(siren_globals_id,zend_siren_globals *,v)
#else
#define SIREN_G(v) (siren_globals.v)
#endif
?
#endif? /* PHP_SIREN_H */
|
上面有几个 PHP_*的函数,他们的作用如下
PHP_MINIT_FUNCTION() 当PHP被装载时,模块启动函数即被Zend引擎调用,这里可以做一些初始化操作
PHP_MSHUTDOWN_FUNCTION() 当PHP完全关闭时,Zend引擎调用的函数,
PHP_RINIT_FUNCTION() 在每次PHP请求开始,请求前启动函数被调用。通常用于管理请求前逻辑。
PHP_RSHUTDOWN_FUNCTION() 在每次PHP请求结束后,请求前关闭函数被调用。经常应用在清理请求前启动函数的逻辑。
PHP_MINFO_FUNCTION() 调用phpinfo()时模块信息函数被呼叫,从而打印出模块信息。
这些函数的代码都定义在siren.c文件中.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
?
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_siren.h"
?
?
static int le_siren;
?
?
?
?
const zend_function_entry siren_functions[] = {
???????? PHP_FE(confirm_siren_compiled,? NULL)??????????
???????? PHP_FE_END?????
};
?
?
zend_module_entry siren_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
???????? STANDARD_MODULE_HEADER,
#endif
???????? "siren" ,
???????? siren_functions,
???????? PHP_MINIT(siren),
???????? PHP_MSHUTDOWN(siren),
???????? PHP_RINIT(siren),??????????????
???????? PHP_RSHUTDOWN(siren),??
???????? PHP_MINFO(siren),
#if ZEND_MODULE_API_NO >= 20010901
???????? "0.1" ,
#endif
???????? STANDARD_MODULE_PROPERTIES
};
?
#ifdef COMPILE_DL_SIREN
ZEND_GET_MODULE(siren)
#endif
?
?
????
????
?
?
????????
????????
?
?
PHP_MINIT_FUNCTION(siren)
{
????????
????????
????????
???????? return SUCCESS;
}
?
?
PHP_MSHUTDOWN_FUNCTION(siren)
{
????????
????????
????????
???????? return SUCCESS;
}
?
?
PHP_RINIT_FUNCTION(siren)
{
???????? return SUCCESS;
}
?
?
PHP_RSHUTDOWN_FUNCTION(siren)
{
???????? return SUCCESS;
}
?
?
PHP_MINFO_FUNCTION(siren)
{
???????? php_info_print_table_start();
???????? php_info_print_table_header(2, "siren support" , "enabled" );
???????? php_info_print_table_end();
?
????????
????????
????????
}
???
PHP_FUNCTION(confirm_siren_compiled)
{
???????? char *arg = NULL;
???????? int arg_len,len;
???????? char *strg;
?
???????? if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,&arg_len) == FAILURE) {
???????????????? return ;
???????? }
?
???????? len = spprintf(&strg,arg);
???????? RETURN_STRINGL(strg,0);
}
|
第21行 zend_function_entry是一个结构体
1
2
3
4
5
6
7
|
typedef struct _zend_function_entry {
???????? const char *fname;
???????? void (*handler)(INTERNAL_FUNCTION_PARAMETERS);?
???????? const struct _zend_arg_info *arg_info;
???????? zend_uint num_args;
???????? zend_uint flags;
} zend_function_entry;
|
1
2
3
4
|
const zend_function_entry siren_functions[] = {
???????? PHP_FE(confirm_siren_compiled,remove later. */
???????? PHP_FE_END?????
};
|
上面就是定义了一个函数数组
PHP_FE是一个宏.
等于
#define ZEND_FENTRY(zend_name,name,arg_info,flags) { #zend_name,(zend_uint) (sizeof(arg_info)/sizeof(struct
_zend_arg_info)-1),flags },
只是做了一些初始化.
PHP_FE_END 等于 { NULL,NULL,0 }
用来结束数组
zend_module_entry 是一个结构体,用来保存模块信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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;
???????? char *build_id;
};
|
主要字段都在代码里注释了
创建一个 zend_module_entry对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
zend_module_entry siren_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
???????? STANDARD_MODULE_HEADER,
#endif
???????? "siren" ,?
???????? siren_functions,
???????? PHP_MINIT(siren),
???????? PHP_MSHUTDOWN(siren),
???????? PHP_RINIT(siren),??
???????? PHP_RSHUTDOWN(siren),?
???????? PHP_MINFO(siren),
#if ZEND_MODULE_API_NO >= 20010901
???????? "0.1" ,
#endif
???????? STANDARD_MODULE_PROPERTIES
};
|
STANDARD_MODULE_HEADER宏:
sizeof(zend_module_entry),ZEND_MODULE_API_NO,ZEND_DEBUG,USING_ZTS
用来填充 前面四个参数
第48行:
只有你的模块编译成 动态模块的时候才会被调用.这个函数的作用就是把模块的信息块传递 给Zend 并通知 Zend 获取这个模块的相关内容
54-57行:
我们在写PHP的时候,php.ini里面的配置都会影响我们PHP代码的执行,比如register_global 等.
此处代码的作用就是获取php.ini里面的配置信息.
1
|
STD_PHP_INI_ENTRY( "siren.global_value" ,????? "42" ,siren_globals)
|
STD_PHP_INI_ENTRY宏:注册php INI的指令:
接受的参数列表如下
name: php.ini里面的名称
default_value: //默认值,永远都是字符串
modifiable: ini可以被改变的地方 值如下
PHP_INI_SYSTEM. 能够在php.ini或http.conf等系统文件更改
PHP_INI_PERDIR. 能够在 .htaccess中更改
PHP_INI_USER. 能够被用户脚本更改
PHP_INI_ALL. 能够在所有地方更改
on_modify: 处理INI条目更改的回调函数。你不需自己编写处理程序,使用下面提供的函数。包括:
OnUpdateInt
OnUpdateString
OnUpdateBool
OnUpdateStringUnempty
OnUpdateReal
property_name: 应当被更新的变量名
struct_type: 变量驻留的结构类型。因为通常使用全局变量机制,所以这个类型自动被定义,类似于zend_myfile_globals。
struct_ptr: 全局结构名。如果使用全局变量机制,该名为myfile_globals。
剩下的东西就是我们上面提到的一些 启动模块时执行的函数…
明白了这些,再去写模块头就不会大啦… (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|