PHP扩展开发课程(摘要)

PHP扩展开发课程(摘要)
PHP是一种解释语言,对于用户来说,我们对内存的仔细控制意味着更容易的原型化和更少的崩溃!当我们深入核心时,所有的安全线都已越过。最终,我们必须依靠真正负责任的软件工程师来确保系统的稳定运行

1,线程安全宏的定义

有在TSRM / TSRM以下定义的.h文件

#定义tsrmls_fetch()无效的*** tsrm_ls =(void *)ts_resource_ex(0,null)

#定义tsrmls_fetch_from_ctx(CTX)无效的*** tsrm_ls =(void *)CTX

#定义tsrmls_set_ctx(CTX)CTX =(void *)tsrm_ls

#定义tsrmg(ID、类型、元素)(((型)(*(* * *)tsrm_ls)){ tsrm_unshuffle_rsrc_id(ID)))->元)

#定义tsrmls_d无效*** tsrm_ls

#定义tsrmls_dc,tsrmls_d

#定义tsrmls_c tsrm_ls

#定义tsrmls_cc,tsrmls_c

有这样一句话在Ext / / H php_xsl XSL。

在每个实用函数中,都需要使用变量。

在php_xsl_globals,叫tsrm_fetch();在宣布其他。

在函数中使用的变量,或者更好的是,通过tsrmls_cc

在最后一个函数参数和声明实用函数之后

与tsrmls_dc在最后声明的参数。总是指

在你的函数的全局变量作为xsl_g(变量)。你是.

鼓励将这些宏重命名为更短的,请参见

任何其他PHP模块目录中的示例。

* /
1。添加tsrmls_d当定义方法(如果方法没有参数使用)或tsrmls_dc(超过1个参数)
2。使用tsrmls_c(如果没有参数了)或tsrmls_cc(超过1个参数)方法调用时被称为。

应该这样理解。

第一个后缀D是D =定义,第一个后缀C是C =调用,第二个后缀字母C是一个逗号。

tsrmls_d定义,所以它是无效的*** tsrm_ls
TSRMLS_DC is a comma definition, so it's void ***tsrm_ls
tsrmls_c是一个电话,那是,tsrm_ls
tsrmls_cc是一个电话和一个逗号,即tsrm_ls
所以一个是参数,一个是实际引用。

它可以用这种方式使用。

国际php_myext_action(int action_id,char *消息tsrmls_dc);

php_myext_action(42,生命的意义tsrmls_cc);

通常建议使用tsrm_ls指针定义以确保线程安全

tsrmls_fetch电话需要一定的处理时间,这是在一次迭代中不明显,但是你的线程数量的增加,当你增加tsrmls_fetch电话数量(),你的扩张将显示这一瓶颈。所以请慎重使用。注:为了与C++编译器兼容,确保tsrmls_fetch()和所有变量的定义放在给定的块范围的顶部(在任何其他语句)。因为tsrmls_fetch()宏本身具有多种不同的分析方法,它是更好地使用它作为一个变量定义的最后一行。

PHP 2的生命周期

PHP的两种工作模式是Web模式和CLI模式。在任何模式,PHP的工作原理是一个SAPI运行相同。

1,当我们处于PHP命令的终端时,它是CLI的使用。

它就像一个Web服务器,支持PHP完成请求,然后在请求完成后将控件替换到终端。

2,当Apache用作主机时,当请求到达时,PHP将支持完成此请求。

php_minit_function运行时模块初始化

php_mshutdown_function运行模块卸载

php_rinit_function运行时初始化请求

php_rshutdown_function在请求请求运行结束

这是php_minfo_function在phpinfo设置本模块的信息

当php_ginit_function初始化全局变量

当php_gshutdown_function释放全局变量

例如,php_ginit_function
php_ginit_function(测试)
{
初始化一个全局变量*
}
对应的C代码
无效zm_globals_ctor_test(zend_test_globals * test_globals tsrmls_dc)
{
初始化一个全局变量*
}
/ /线程退出,将需要申请自己的资源发布前,你可以登记使用php_gshutdown_function析构函数。
php_gshutdown_function(测试)
{
删除全局变量*
}
对应的C代码
无效zm_globals_dtor_test(zend_test_globals * test_globals tsrmls_dc)
{
删除全局变量*
}
这里有一段可以测试的代码。
国际minit_time;
php_minit_function(测试)
{
minit_time =时间(空);
返回成功;
}
php_mshutdown_function(测试)
{
文件= fopen(mshutdown .txt
Fprintf(FP,%ld
Fclose(FP);
返回成功;
}
国际rinit_time;
php_rinit_function(测试)
{
rinit_time =时间(空);
返回成功;
}
php_rshutdown_function(测试)
{
文件= fopen(rshutdown .txt
Fprintf(FP,%ld
Fclose(FP);
返回成功;
}
php_minfo_function(测试)
{
php_info_print_table_start();
php_info_print_table_header(模块信息
php_info_print_table_end();
如果你的作品/在php.ini中删除注释
display_ini_entries();
* /
}
php_function(测试)
{
php_printf(%d
php_printf(%d
返回;
}
3,分段错误调试
Linux下的C程序往往会造成部分故障引起的内存访问错误(段措武)此时如果系统核心转储启用,然后将内存转储到硬盘上,然后可以解析核心文件与GDB,减少堆栈系统出错的时候。这是我们的程序错误的发现很有帮助。

使用ulimit -可以查看系统核心文件大小限制;使用ulimit C {字节}可以设置,系统可以生成核心文件的大小。

ulimit C 0不产生核心文件

ulimit C 100集的最大核心文件是100k

ulimit C无限不限制核心文件的大小

步:

1。当一段错误发生,我们看看ulimit -(核心文件大小(块,C)0)和没有文件,

2集:ulimit C无限不限制核心文件的大小

三.运行程序是自动记录的核心(F workwitharray PHP。PHP)当一段错误发生。

4、LS型铝芯。*在文件(刻录------- 1 Leconte Leconte 139264 01-06 22:31核心。2065)

5。使用GDB运行程序并记录段错误记录。(2065)

6,这是错误的。

许多系统默认核心文件的大小是0。我们可以将核心文件大小加入ulimit -c command shell的启动脚本 / / bashrc等或~ / .bashrc,确保核心可以生成文件。

此外,你还可以在/proc / / / core_pattern内核系统核心文件的文件名设置模板,并详见核心官方说明书的人。

4。公共变量操作

CG ->编译器编译时信息的全球,包括功能表(zend_globals_macros。H:32)

如->执行执行全球信息(zend_globals_macros。H:43)

PG PHP核心全球->主要存储信息的

SG -> SAPI全球SAPI
1、SG在主/ SAPI SAPI H文件信息。
_sapi_globals_struct { typedef struct
void * server_context;
sapi_request_info request_info;
sapi_headers_struct sapi_headers;
国际read_post_bytes;
unsigned char headers_sent;
global_stat struct stat;
char * default_mimetype;
char * default_charset;
* rfc1867_uploaded_files哈希表;
长post_max_size;
INT选项
zend_bool sapi_started;
双global_request_time;
哈希表known_post_content_types;
* callback_func zval;
zend_fcall_info_cache fci_cache;
zend_bool callback_run;
sapi_globals_struct };
看SG的定义

begin_extern_c()

# ifdef特稿

#定义SG(V)tsrmg(sapi_globals_id,sapi_globals_struct,V)

sapi_api extern int sapi_globals_id;

其他#

#定义SG(V)(sapi_globals。V)

外部sapi_api sapi_globals_struct sapi_globals;

# endif

sapi_api无效sapi_startup(sapi_module_struct * SF);

sapi_shutdown sapi_api虚空(void);

sapi_api无效sapi_activate(tsrmls_d);

sapi_api无效sapi_deactivate(tsrmls_d);

sapi_api无效sapi_initialize_empty_request(tsrmls_d);

end_extern_c()

成员在sapi_globals_struct

所以我可以这样称呼它

SG(default_mimetype)

SG(request_info request_uri)。

你可以感觉到这样一段代码
静态变量sapi_cgi_send_headers(sapi_headers_struct * sapi_headers tsrmls_dc)
{
sapi_cgi_max_header_length中字符{ };
sapi_header_struct×h;
zend_llist_position POS;
长rfc2616_headers = 0;
如果(SG(request_info)。no_headers = = 1){
返回sapi_header_sent_successfully;
}
如果(SG(sapi_headers http_response_code)!= 200){
Int len;
len = sprintf(buf,状态:%d R
phpwrite_h(buf,Len);
}
如果(SG(sapi_headers)。send_default_content_type){
字符*;
高清= sapi_get_default_content_type(tsrmls_c);
phpwrite_h(内容类型
phpwrite_h(HD,strlen(HD));
phpwrite_h( R
依芙利特(高清);
}
H = zend_llist_get_first_ex(sapi_headers ->页眉,POS);
当(h){
phpwrite_h(H ->页眉、H > header_len);
phpwrite_h( R
H = zend_llist_get_next_ex(sapi_headers ->页眉,POS);
}
phpwrite_h( R
返回sapi_header_sent_successfully;
}
2、如执行全局

如获取数据结构中_zend_execution_globals结构
结构_zend_execution_globals {

哈希表symbol_table; / *全球范围,如果没有访问内部功能,全球活动= * /
哈希表* active_symbol_table; / *活动范围在当前的范围。

}
通常,EG的使用(symbol_table)是全球范围内的一个符号表,和EG的使用(active_symbol_table)是当前范围下的符号表

例如,定义变量$foo = 'bar

* fooval zval;
make_std_zval(fooval);

zval_string(fooval,酒吧

zend_set_symbol(如(active_symbol_table),foo
或者从符号表中查找$

* fooval zval;

如果(zend_hash_find(如(symbol_table),foo

return_stringl(z_strval_pp(fooval),z_strlen_pp(fooval));

{人}

return_false;

}

上面的代码,如(active_symbol_table)=如(symbol_table)

3、CG()用于访问核心全局变量。(Zend / zend_globals_macros。H)

4、PG()全局变量。我们知道的将地图的一个或多个PHP全局结构。(主/ php_globals。H)

5,FG()文件全局变量。大多数文件I/O或相关全局变量的数据流被卡在标准扩展导出结构中。

5。获取变量的类型和值。

#定义z_type(机制)(zval类型)。

#定义z_type_p(zval_p)z_type(* zval_p)

#定义z_type_pp(zval_pp)z_type(** zval_pp)

获取变量的类型,例如
无效describe_zval(zval * foo)
{
如果(z_type_p(Foo)= is_null)
{
php_printf(这一变量的数据类型是:空);
}
其他的
{
php_printf(数据类型的变量不为空,此数据类型对应的号码:%d
}
}
有这些类型

#定义is_null 0

#定义is_long 1

#定义is_double 2

#定义is_bool 3

#定义is_array 4

#定义is_object 5

#定义is_string 6

#定义is_resource 7

#定义is_constant 8

#定义is_constant_array 9

#定义is_callable 10

的php_printf()函数printf()函数的内核封装。我们可以使用它作为一个printf()函数。最为一个宏观的P终止参数*变量的变量。此外,有两个变量得到的变量的类型,这是z_type和z_type_pp,前者是变量,后者是** zval

如GetType函数的实现
/ / PHP语言的功能定义在GetType
php_function(方法)
{
/ /精氨酸间接指向参数,通过GetType函数被调用时,它是一个zval结构简单
所以我们要用他/ __pp后缀宏观。
zval **精;
此操作主要是if /参数来生成点。
如果(zend_parse_parameters(zend_num_args)(tsrmls_cc,Z,Arg)= =失败){
返回;
}
型 / / z_type_pp宏调用ARG zval。
然后是一个字符串类型的开关结构,表示方法retval_string宏函数返回值
开关(z_type_pp(Arg)){
案例is_null:
retval_string(空
打破;
案例is_bool:
retval_string(布尔
打破;
案例is_long:
retval_string(整
打破;
案例is_double:
retval_string(双
打破;
案例is_string:
retval_string(字符串
打破;
案例is_array:
retval_string(阵列
打破;
案例is_object:
retval_string(对象
打破;
案例is_resource:
{
Char *type_name;
type_name = zend_rsrc_list_get_rsrc_type(z_lval_pp(Arg)tsrmls_cc);
如果(type_name){
retval_string(资源
打破;
}
}
违约:
retval_string(未知类型
}
}
获取变量的值,并得到这么多宏


布尔

字符串值
字符串的长度
z_lval()
z_bval()
z_dval()
z_strval()
z_strlen()
z_lval_p()
z_bval_p()
z_dval_p()
z_strval_p()
z_strlen_p()
z_lval_pp()
z_bval_pp()
z_dval_pp()
z_strval_pp()
z_strlen_pp()

散列表
对象
对象的属性
对象类条目
资源价值
z_arrval()
z_obj()
z_objprop()
z_objce()
z_resval()
z_arrval_p()
z_obj_p()
z_objprop_p()
z_objce_p()
z_resval_p()
z_arrval_pp()
z_obj_pp()
z_objprop_pp()
z_objce_pp()
z_resval_pp()

对用rot13编码功能的实现
php_function(rot13)
{
zval **精;
字符*;
int i;

如果(zend_num_args)(zend_get_parameters_ex = 1 | |!(1,精氨酸)=失败){
wrong_param_count;
}
* return_value =××精氨酸;
zval_copy_ctor(return_value);
convert_to_string(return_value);

为(i = 0,CH = return_value -> value.str.val;
Ivalue.str.len;我+ +,CH + +){
上限=CH 32;
*上限;
* CH =((* CH > = 'a')(* CH <= Z)((* CH - A + 13)% 26 + A):* CH)|帽;
}
}
把这个变量的值,还应使用由Zend定义的宏来访问。简单的标量数据类型、布尔、长、双、使用z_bval,z_lval,z_dval
无效display_values(zval boolzv,zval * longpzv,zval ** doubleppzv)
{
如果(z_type(boolzv)= = is_bool){
php_printf(的价值逻辑是:%s
}
如果(z_type_p(longpzv)= = is_long){
php_printf(值长:%ld
}
如果(z_type_pp(doubleppzv)= = is_double){
php_printf(价值的双重:%f
}
}
对于字符串类型,因为它包含两个字段,char *(z_strval)和int(z_strlen),所以我们要用两个宏来获得价值,因为二进制安全输出字符串是必要的。
无效display_string(zval * zstr)
{
如果(z_type_p(zstr)!= is_string){
php_printf(wronng类型了!;
返回;
}
phpwrite(z_strval_p(zstr),z_strlen_p(zstr));
}
由于阵列存在于哈希表中变量的形式,z_arrval()用于访问
无效display_zval(zval *值)
{
开关(z_type_p(值)){
案例is_null:
如果它是空的,则不输出任何内容。
打破;

案例is_bool:
如果是布尔型的,而真实,则输出1,否则什么也不干。
如果(z_bval_p(值)){
php_printf(1 );
}
打破;
案例is_long:
*如果长整型,则输出数字形式。
php_printf(%ld
打破;
案例is_double:
如果为双,则浮点的输出。
php_printf(% F
打破;
案例is_string:
如果是字符串,则输出二进制安全字符串。
phpwrite(z_strval_p(值),z_strlen_p(值));
打破;
案例is_resource:
如果 /资源,输出资源# 10格式*的东东
php_printf(资源# %ld
打破;
案例is_array:
/ *如果是阵列的输出,array5字母!* /
php_printf(数组);
打破;
案例is_object:
php_printf(对象);
打破;
违约:
在实践中决不发生,
*做假设是危险的。
* /
php_printf(未知);
打破;
}
}
某些类型的转换函数

zend_api无效convert_to_long(zval * OP);

zend_api无效convert_to_double(zval * OP);

zend_api无效convert_to_null(zval * OP);

zend_api无效convert_to_boolean(zval * OP);

zend_api无效convert_to_array(zval * OP);

zend_api无效convert_to_object(zval * OP);

zend_api无效_convert_to_string(zval *运算zend_file_line_dc);

6,常量实例化

我们可以实例化这个
php_minit_function(常量) /模块的初始化定义的常量
{
register_long_constant(consts_meaning_of_life
register_double_constant(consts_pi
register_string_constant(consts_name
}
php_rinit_function(常量) / /常量定义为每个请求
{
char缓冲区{ 40 };
Srand((int)时间(空));
Snprintf(缓冲,sizeof(缓冲区),%d
register_string_constant(consts_rand
返回成功;
}
常见的宏

长类型常数**寄存器

#定义register_long_constant(名称、语句、旗)zend_register_long_constant((名字),sizeof(姓名),(语句),(旗),module_number)
双类型常数***寄存器

#定义register_double_constant(名称,dval,标志)zend_register_double_constant((名字),sizeof(姓名),(双)、(旗),module_number)
字符串类型常量

#定义register_string_constant(名称、STR、旗)zend_register_string_constant((名字),sizeof(姓名),(STR),(旗),module_number)
字符串类型常量

#定义register_stringl_constant(名称,STR,Len,标志)zend_register_stringl_constant((名字),sizeof(姓名),(STR)、(、)、(x),X。

7。全局变量
生成后的| # php-fpm得到|饼干|服务器| env |请求|文件全局变量的过程
(php_cgi_startup)php_module_startup(php_startup_auto_globals)> >()->保存变量symbol_table符号表
php_cgi_startup()是定义在FPM / / fpm_main C程序。
php_module_startup()在主/主定义的C。
php_startup_auto_globals()在主/ php_variables H定义。
zend_hash_update(如(symbol_table),_get
读_server美元变 / * * /
静态php_function(print_server_vars){
zval **瓦尔;
如果(zend_hash_find(如(symbol_table),_server
return_zval(* Val,1, 0);
其他{ }
return_false;
}
}
读_server {姓名}美元美元 / * * /
zend_begin_arg_info(print_server_var_arginfo,0)
zend_arg_info(0,名字)
zend_end_arg_info()
静态php_function(print_server_var){
char *名称;
国际name_len;
zval **瓦尔;
哈希表* ht_vars = null;
hashposition POS;
* ret_val zval;
如果(zend_parse_parameters(zend_num_args)(tsrmls_cc,| S!
return_null();
}
如果(zend_hash_find(如(symbol_table),_server
ht_vars = z_arrval_pp(Val);
这里需要扩展长度多于名称 + + 1值,因为后面的字符串值是 0
如果(zend_hash_find(ht_vars,名字,name_len + 1,ret_val(void))= =成功){ return_string(z_strval_pp(ret_val),0);
其他{ }
return_null();
}
其他{ }
return_null();
}
}
8、包装第三方图书馆

配置(M4)
search_path = / usr /局部/ usr # lib目录搜索
路径的search_for = / / /包括卷曲卷曲。H#库头文件
如果测试php_libs美元/美元search_for;然后
libs_dir = $ php_libs
其他搜索默认路径列表#
ac_msg_checking({ LIBS文件的默认路径})
我在做search_path美元;
如果测试R $我/ search_for美元;然后
路径搜索libs_dir = $我#库
ac_msg_result(找到我)
FI
多恩
FI
以验证是否存在此选项。
如果测试Zlibs_dir美元;然后
ac_msg_result({没有发现})
ac_msg_error({请重装LIBS分布})
FI
当添加库 / *编译包含目录,我 / usr /包括/
php_add_include($ libs_dir /:)
库名=卷曲#库名称
一个libsymbol = curl_version #库函数,这是用来php_check_library验证库
库的验证
php_check_library($库名,libsymbol美元,
{
php_add_library_with_path($库名,libs_dir美元/ php_libdir美元,libs_shared_libadd)#编译时链接库,- llibcurl
ac_define(have_libslib,1,{ })
{ }。
ac_msg_error({错版或库没有发现LIBS库})
{ }。
我libs_dir美元/美元php_libdir lm
})
php_subst(libs_shared_libadd)
9。用于返回的宏

在Zend / / / zend_api定义这些宏。h文件。

#定义retval_resource(L)zval_resource(return_value,L)

#定义retval_bool(B)zval_bool(return_value,B)

#定义retval_null()zval_null(return_value)

#定义retval_long(L)zval_long(return_value,L)

#定义retval_double(D)zval_double(return_value,D)

#定义retval_string(s,重复)zval_string(return_value,S,重复)

#定义retval_stringl(S,L,重复)zval_stringl(return_value,S,L,重复)

#定义retval_empty_string()zval_empty_string(return_value)

#定义retval_zval(ZV,复制,中签率)zval_zval(return_value,ZV,复制,中签率)

#定义retval_false zval_bool(return_value,0)

#定义retval_true zval_bool(return_value,1)

#定义return_resource(L){ retval_resource(L);返回;}

#定义return_bool(b){ retval_bool(B);返回;}

#定义return_null(){ retval_null();返回;}

#定义return_long(L){ retval_long(L);返回;}

#定义return_double(D){ retval_double(D);返回;}

#定义return_string(s,重复){ retval_string(s,重复);返回;}

#定义return_stringl(S,L,重复){ retval_stringl(S,L,重复);返回;}。

#定义return_empty_string(){ retval_empty_string();返回;}

#定义return_zval(ZV,复制,中签率){ retval_zval(ZV,复制,中签率);返回;}。

#定义return_false { retval_false;回报;}

#定义return_true { retval_true;回报;}

事实上,除了这些标量类型外,PHP语言中还有许多复合类型。我们需要将它们返回到函数中,比如数组和对象。我们可以操纵他们通过retval_zval和return_zval。

10、哈希表的遍历功能

基于密钥的长/操作函数

zval×V3;

make_std_zval(V3);

zval_string(V3,值

zend_hash_index_update(地名,0,V3,sizeof(zval *),null); / /数字密钥更新根据哈希表中的元素的值

zval * V4;

zend_hash_index_find(地名,1,V4); / /根据指标数获得哈希表中的元素的值

php_printf(V4:);

phpwrite(z_strval_pp(V4),z_strlen_pp(V4));

php_printf(;

页编号;

IDX = zend_hash_index_exists(名10); / /搜索数字索引的哈希表,如果发现返回1,否则返回0

zend_hash_index_del(名2); / /删除索引根据哈希表中的元素个数

/ /哈希表的遍历功能

zend_hash_internal_pointer_reset(地名); / /初始化哈希函数指针

zend_hash_internal_pointer_reset_ex(名字,POS); / /初始化哈希值指针,并支付POS

zend_hash_get_current_data(名字(void *)Val); / /得到散列数据的当前值应该抛储,无效**,即:(void *)数据

zend_hash_get_current_data_ex(名字(void *),瓦迩,POS)= =成功; / /得到散列存储的当前值

zend_hash_get_current_key(名字,关键,该指数为0,hash_key_is_long)

zend_hash_get_current_key_ex(名字,关键,该,指数,0,POS)= = hash_key_is_long; / /哈希表来读取当前的键,返回值将是两hash_key_is_long | hash_key_is_string,对应阵列(价值),阵列(关键=值)两个哈希表

zend_hash_move_forward(地名);

zend_hash_move_forward_ex(名字,POS); / /哈希函数指针指向下一个

/ /哈希表的长度

php_printf(% * CArray(%d){

一个简单的函数
功能hello_array_strings($ ARR){
如果(!is_array($ ARR))返回null;
printf(阵列通过包含%d元素
foreach(ARR美元美元数据){
如果(is_string($数据))回声美元数据;
}
}
PHP内核的实现
php_function(hello_array_strings)
{
* * *数据变量arr;
* arr_hash哈希表;
hashposition指针;
国际array_count;
如果(zend_parse_parameters(zend_num_args)(tsrmls_cc,一,ARR)= =失败){
return_null();
}
arr_hash = z_arrval_p(ARR);
array_count = zend_hash_num_elements(arr_hash);
php_printf(数组传递包含%d元素
对于(zend_hash_internal_pointer_reset_ex(arr_hash,指针);zend_hash_get_current_data_ex(arr_hash(void *),数据指针)= =成功;zend_hash_move_forward_ex(arr_hash,指针)){
如果(z_type_pp(数据)= = is_string){
phpwrite(z_strval_pp(数据),z_strlen_pp(数据));
php_printf();
}
}
return_true;
}
以上是本文的介绍,对php扩展开发课程,希望大家喜欢。
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部