PHP扩展开发教程(总结)
|
PHP是一种解释型的语言,对于用户而言,我们精心的控制内存意味着easier prototyping和更少的崩溃!当我们深入到内核之后,所有的安全防线都已经被越过,最终还是要依赖于真正有责任心的软件工程师来保证系统的稳定运行。 在TSRM/TSRM.h文件中有如下定义 #define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0,NULL) #define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx #define TSRMLS_SET_CTX(ctx) ctx = (void ***) tsrm_ls #define TSRMG(id,type,element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element) #define TSRMLS_D void ***tsrm_ls #define TSRMLS_DC,TSRMLS_D #define TSRMLS_C tsrm_ls #define TSRMLS_CC,TSRMLS_C 在ext/xsl/php_xsl.h有这么一段话 /* In every utility function you add that needs to use variables. in php_xsl_globals,call TSRM_FETCH(); after declaring other. variables used by that function,or better yet,pass in TSRMLS_CC after the last function argument and declare your utility function with TSRMLS_DC after the last declared argument. Always refer to the globals in your function as XSL_G(variable). You are. encouraged to rename these macros something shorter,see examples in any other php module directory. */ 1.在方法定义时加上TSRMLS_D(如果方法没有参数用这个)或者TSRMLS_DC(有1个以上的参数) 2.在方法调用时用TSRMLS_C(如果方法没有参数用这个)或者TSRMLS_CC(有1个以上的参数) 应该可以这样理解 第一个后缀字母D表示定义,即D=Define,第一个后缀字母C表示调用,即C=Call,而第二个后缀字母C是不是表示逗号呢? C=Comma (逗号) TSRMLS_D就是定义了,所以是 void ***tsrm_ls TSRMLS_DC是带逗号的定义,所以是,void ***tsrm_ls TSRMLS_C是调用,即tsrm_ls TSRMLS_CC是调用并带逗号,即,tsrm_ls 所以一个是形参、一个是实参 可以这样使用 int php_myext_action(int action_id,char *message TSRMLS_DC); php_myext_action(42,"The meaning of life" TSRMLS_CC); 一般推荐使用tsrm_ls指针定义的方式来保证线程安全 TSRMLS_FETCH调用需要一定的处理时间。这在单次迭代中并不明显,但是随着你的线程数增多,随着你调用TSRMLS_FETCH()的点的增多,你的扩展就会显现出这个瓶颈。因此,请谨慎的使用它。 注意:为了和c++编译器兼容,请确保将TSRMLS_FETCH()和所有变量定义放在给定块作用域的顶部(任何其他语句之前)。因为TSRMLS_FETCH()宏自身有多种不同的解析方式,因此最好将它作为变量定义的最后一行 2、PHP的生命周期 PHP的最多的两种运行模式是WEB模式、CLI模式,无论哪种模式,PHP工作原理都是一样的,作为一种SAPI运行。 1、当我们在终端敲入php这个命令的时候,它使用的是CLI。 它就像一个web服务器一样来支持php完成这个请求,请求完成后再重新把控制权交给终端。 2、当使用Apache作为宿主时,当一个请求到来时,PHP会来支持完成这个请求 PHP_MINIT_FUNCTION 初始化module时运行 PHP_MSHUTDOWN_FUNCTION 当module被卸载时运行 PHP_RINIT_FUNCTION 当一个REQUEST请求初始化时运行 PHP_RSHUTDOWN_FUNCTION 当一个REQUEST请求结束时运行 PHP_MINFO_FUNCTION 这个是设置phpinfo中这个模块的信息 PHP_GINIT_FUNCTION 初始化全局变量时 PHP_GSHUTDOWN_FUNCTION 释放全局变量时 比如PHP_GINIT_FUNCTION 这里有一段代码,可以测试一下 3、段错误调试 Linux下的C程序常常会因为内存访问错误等原因造成segment fault(段错误)此时如果系统core dump功能是打开的,那么将会有内存映像转储到硬盘上来,之后可以用gdb对core文件进行分析,还原系统发生段错误时刻的堆栈情况。这对于我们发现程序bug很有帮助。 使用ulimit -a可以查看系统core文件的大小限制;使用ulimit -c [kbytes]可以设置系统允许生成的core文件大小。 ulimit -c 0 不产生core文件 ulimit -c 100 设置core文件最大为100k ulimit -c unlimited 不限制core文件大小 步骤: 1、当发生段错误时,我们查看ulimit -a (core file size (blocks,-c) 0)并没有文件, 2、设置 :ulimit -c unlimited 不限制core文件大小 3、运行程序 ,发生段错误时会自动记录在core中 (php -f WorkWithArray.php) 4、ls -al core.* 在那个文件下(-rw------- 1 leconte leconte 139264 01-06 22:3 1 core.2065) 5、使用gdb 运行程序和段错误记录的文件。(gdb ./test core.2065) 6、会提哪行有错。 很多系统默认的core文件大小都是0,我们可以通过在shell的启动脚本/etc/bashrc或者~/.bashrc等地方来加入 ulimit -c 命令来指定core文件大小,从而确保core文件能够生成。 除此之外,还可以在/proc/sys/kernel/core_pattern里设置core文件的文件名模板,详情请看core的官方man手册。 4、常见的变量操作宏 CG -> Complier Global 编译时信息,包括函数表等(zend_globals_macros.h:32) EG -> Executor Global 执行时信息(zend_globals_macros.h:43) PG -> PHP Core Global 主要存储php.ini中的信息 SG -> SAPI Global SAPI信息 1、SG 针对SAPI信息 在main/SAPI.h文件中 看一下SG的定义 BEGIN_EXTERN_C() #ifdef ZTS # define SG(v) TSRMG(sapi_globals_id,sapi_globals_struct *,v) SAPI_API extern int sapi_globals_id; #else # define SG(v) (sapi_globals.v) extern SAPI_API sapi_globals_struct sapi_globals; #endif SAPI_API void sapi_startup(sapi_module_struct *sf); SAPI_API void sapi_shutdown(void); SAPI_API void sapi_activate(TSRMLS_D); SAPI_API void sapi_deactivate(TSRMLS_D); SAPI_API void sapi_initialize_empty_request(TSRMLS_D); END_EXTERN_C() 成员都在sapi_globals_struct这里了 那么我么可以这样调用 SG(default_mimetype) SG(request_info).request_uri 可以感受一下这么一段代码 headers,&pos);
while (h) {
PHPWRITE_H(h->header,h->header_len);
PHPWRITE_H("rn",2);
h = zend_llist_get_next_ex(&sapi_headers->headers,&pos);
}
PHPWRITE_H("rn",2);
return SAPI_HEADER_SENT_SUCCESSFULLY;
}
2、EG Executor Globals EG获取的是struct _zend_execution_globals结构体中的数据 通常,使用EG(symbol_table)获取的是全局作用域中的符号表,使用EG(active_symbol_table)获取的是当前作用域下的符号表 例如 来定义$foo = 'bar' zval *fooval; MAKE_STD_ZVAL(fooval); 或者从符号表中查找$foo zval **fooval; if(zend_hash_find(&EG(symbol_table),sizeof("foo"),(void **)&fooval) == SUCCESS) { RETURN_STRINGL(Z_STRVAL_PP(fooval),Z_STRLEN_PP(fooval)); } else { RETURN_FALSE; } 上面的代码中,EG(active_symbol_table) == &EG(symbol_table) 3、CG() 用来访问核心全局变量。(zend/zend_globals_macros.h) 4、PG() PHP全局变量。我们知道php.ini会映射一个或者多个PHP全局结构。(main/php_globals.h) 5、FG() 文件全局变量。大多数文件I/O或相关的全局变量的数据流都塞进标准扩展出口结构。(ext/standard/file.h) 5、获取变量的类型和值 #define Z_TYPE(zval) (zval).type #define Z_TYPE_P(zval_p) Z_TYPE(*zval_p) #define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp) 比如获取一个变量的类型 有这么几种类型(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
