PHP_GINIT_FUNCTION(test){/** 初始化全局变量 */}//对应的C代码void zm_globals_ctor_test (zend_test_globals *test_globals TSRMLS_DC){/** 初始化全局变量 */}//在线程退出时,需要将之前自己申请的资源释放时,可以使用 PHP_GSHUTDOWN_FUNCTION来注册析构函数。PHP_GSHUTDOWN_FUNCTION(test){/** 清除全局变量 */}//对应的C代码void zm_globals_dtor_test (zend_test_globals *test_globals TSRMLS_DC){/** 清除全局变量 */}这里有一段代码,可以测试一下int minit_time;PHP_MINIT_FUNCTION(test){minit_time = time(NULL);return SUCCESS;}PHP_MSHUTDOWN_FUNCTION(test){FILE *fp=fopen("mshutdown.txt","a+");fprintf(fp,"%ld
",time(NULL));fclose(fp);return SUCCESS;}int rinit_time;PHP_RINIT_FUNCTION(test){rinit_time = time(NULL);return SUCCESS;}PHP_RSHUTDOWN_FUNCTION(test){FILE *fp=fopen("rshutdown.txt","a+");fprintf(fp,"%ld
",time(NULL));fclose(fp);return SUCCESS;}PHP_MINFO_FUNCTION(test){php_info_print_table_start();php_info_print_table_header(, "module info", "enabled");php_info_print_table_end();/* Remove comments if you have entries in php.iniDISPLAY_INI_ENTRIES();*/}PHP_FUNCTION(test){php_printf("%d",time_of_minit);php_printf("%d",time_of_rinit);return;}3、段错误调试typedef struct _sapi_globals_struct {void *server_context;sapi_request_info request_info;sapi_headers_struct sapi_headers;int read_post_bytes;unsigned char headers_sent;struct stat global_stat;char *default_mimetype;char *default_charset;HashTable *rfc1867_uploaded_files;long post_max_size;int options;zend_bool sapi_started;double global_request_time;HashTable known_post_content_types;zval *callback_func;zend_fcall_info_cache fci_cache;zend_bool callback_run;} sapi_globals_struct;看一下SG的定义static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC){char buf[SAPI_CGI_MAX_HEADER_LENGTH];sapi_header_struct *h;zend_llist_position pos;long rfc2616_headers = 0;if(SG(request_info).no_headers == 1) {return SAPI_HEADER_SENT_SUCCESSFULLY;}if (SG(sapi_headers).http_response_code != 200) {int len;len = sprintf(buf, "Status: %d
", SG(sapi_headers).http_response_code);PHPWRITE_H(buf, len);}if (SG(sapi_headers).send_default_content_type) {char *hd;hd = sapi_get_default_content_type(TSRMLS_C);PHPWRITE_H("Content-type:", sizeof("Content-type: ")-1);PHPWRITE_H(hd, strlen(hd));PHPWRITE_H("
", 2);efree(hd);}h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);while (h) {PHPWRITE_H(h->header, h->header_len);PHPWRITE_H("
", 2);h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);}PHPWRITE_H("
", 2);return SAPI_HEADER_SENT_SUCCESSFULLY;} 2、EG Executor Globalsstruct _zend_execution_globals { ... HashTable symbol_table;/* 全局作用域,如果没有进入函数内部,全局=活动 */ HashTable *active_symbol_table; /* 活动作用域,当前作用域 */ ...}通常,使用EG(symbol_table)获取的是全局作用域中的符号表,使用EG(active_symbol_table)获取的是当前作用域下的符号表void describe_zval(zval *foo){if ( Z_TYPE_P(foo) == IS_NULL ){php_printf("这个变量的数据类型是: NULL");}else{php_printf("这个变量的数据类型不是NULL,这种数据类型对应的数字是: %d", Z_TYPE_P(foo));}}有这么几种类型//开始定义php语言中的函数gettypePHP_FUNCTION(gettype){//arg间接指向调用gettype函数时所传递的参数。是一个zval**结构//所以我们要对他使用__PP后缀的宏。zval **arg;//这个if的操作主要是让arg指向参数~if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {return;}//调用Z_TYPE_PP宏来获取arg指向zval的类型。//然后是一个switch结构,RETVAL_STRING宏代表这gettype函数返回的字符串类型的值switch (Z_TYPE_PP(arg)) {case IS_NULL:RETVAL_STRING("NULL", 1);break;case IS_BOOL:RETVAL_STRING("boolean", 1);break;case IS_LONG:RETVAL_STRING("integer", 1);break;case IS_DOUBLE:RETVAL_STRING("double", 1);break;case IS_STRING:RETVAL_STRING("string", 1);break;case IS_ARRAY:RETVAL_STRING("array", 1);break;case IS_OBJECT:RETVAL_STRING("object", 1);break;case IS_RESOURCE:{char *type_name;type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(arg) TSRMLS_CC);if (type_name) {RETVAL_STRING("resource", 1);break;}}default:RETVAL_STRING("unknown type", 1);}}获取变量的值,有这么多宏来获取Long | Boolean | Double | String value | String length |
|---|---|---|---|---|
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( ) |
HashTable | Object | Object properties | Object class entry | Resource value |
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( ) |
PHP_FUNCTION(rot13){ zval **arg; char *ch, cap; int i; if (ZEND_NUM_ARGS( ) != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) { WRONG_PARAM_COUNT; } *return_value = **arg; zval_copy_ctor(return_value); convert_to_string(return_value); for(i=0, ch=return_value->value.str.val; i<return_value->value.str.len; i++, ch++) {cap = *ch & 32;*ch &= ~cap;*ch = ((*ch>="A") && (*ch<="Z") ? ((*ch-"A"+13) % 26 + "A") : *ch) | cap;}}要获取变量的值,也应该使用Zend定义的宏进行访问。对于简单的标量数据类型、Boolean,long,double, 使用Z_BVAL, Z_LVAL, Z_DVALvoid display_values(zval boolzv, zval *longpzv, zval **doubleppzv){ if (Z_TYPE(boolzv) == IS_BOOL) {php_printf("The value of the boolean is : %s
", Z_BVAL(boolzv) ? "true" : "false"); } if(Z_TYPE_P(longpzv) == IS_LONG) {php_printf("The value of the long is: %ld
", Z_LVAL_P(longpzv)); } if(Z_TYPE_PP(doubleppzv) == IS_DOUBLE) {php_printf("The value of the double is : %f
", Z_DVAL_PP(doubleppzv)); }}对于字符串类型,因为它含有两个字段char * (Z_STRVAL) 和 int (Z_STRLEN),因此需要用两个宏来进行取值,因为需要二进制安全的输出这个字符串void display_string(zval *zstr){ if (Z_TYPE_P(zstr) != IS_STRING) {php_printf("The wronng datatype was passed!
");return ; } PHPWRITE(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr));}因为数组在zval中是以HashTable形式存在的,因此使用Z_ARRVAL()进行访问void display_zval(zval *value){switch (Z_TYPE_P(value)) {case IS_NULL:/* 如果是NULL,则不输出任何东西 */break; case IS_BOOL:/* 如果是bool类型,并且true,则输出1,否则什么也不干 */if (Z_BVAL_P(value)) {php_printf("1");}break;case IS_LONG:/* 如果是long整型,则输出数字形式 */php_printf("%ld", Z_LVAL_P(value));break;case IS_DOUBLE:/* 如果是double型,则输出浮点数 */php_printf("%f", Z_DVAL_P(value));break;case IS_STRING:/* 如果是string型,则二进制安全的输出这个字符串 */PHPWRITE(Z_STRVAL_P(value), Z_STRLEN_P(value));break;case IS_RESOURCE:/* 如果是资源,则输出Resource #10 格式的东东 */php_printf("Resource #%ld", Z_RESVAL_P(value));break;case IS_ARRAY:/* 如果是Array,则输出Array5个字母! */php_printf("Array");break;case IS_OBJECT:php_printf("Object");break;default:/* Should never happen in practice, * but it"s dangerous to make assumptions */ php_printf("Unknown"); break;}} 一些类型转换函数PHP_MINIT_FUNCTION(consts) //模块初始化时定义常量{REGISTER_LONG_CONSTANT("CONSTS_MEANING_OF_LIFE", 42, CONST_CS | CONST_PERSISTENT);REGISTER_DOUBLE_CONSTANT("CONSTS_PI", 3.1415926, CONST_PERSISTENT);REGISTER_STRING_CONSTANT("CONSTS_NAME", "leon", CONST_CS|CONST_PERSISTENT);}PHP_RINIT_FUNCTION(consts) //每次请求时定义常量{char buffer[40];srand((int)time(NULL));snprintf(buffer, sizeof(buffer), "%d", rand());REGISTER_STRING_CONSTANT("CONSTS_RAND", estrdup(buffer), CONST_CS);return SUCCESS;}常见的宏#php-fpm 生成 POST|GET|COOKIE|SERVER|ENV|REQUEST|FILES全局变量的流程php_cgi_startup() -> php_module_startup() -> php_startup_auto_globals() -> 保存变量到symbol_table符号表php_cgi_startup()在 fpm/fpm/fpm_main.c中定义php_module_startup() 在main/main.c中定义php_startup_auto_globals() 在main/php_variables.h中定义zend_hash_update(&EG(symbol_table), "_GET", sizeof("_GET") + 1, &vars, sizeof(zval *), NULL);/* 读取$_SERVER变量 */static PHP_FUNCTION(print_server_vars) {zval **val;if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {RETURN_ZVAL(*val, 1, 0);}else{ RETURN_FALSE;}}/* 读取$_SERVER[$name] */ZEND_BEGIN_ARG_INFO(print_server_var_arginfo, 0)ZEND_ARG_INFO(0, "name")ZEND_END_ARG_INFO()static PHP_FUNCTION(print_server_var) {char *name;int name_len;zval **val;HashTable *ht_vars = NULL;HashPosition pos;zval **ret_val;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &name_len) == FAILURE) {RETURN_NULL();}if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) {ht_vars = Z_ARRVAL_PP(val);//此处需传入大于name长度+1的值,因为字符串值后面需要" "if (zend_hash_find(ht_vars, name, name_len+1, (void **)&ret_val) == SUCCESS) { RETURN_STRING(Z_STRVAL_PP(ret_val), 0);}else{RETURN_NULL();}}else{RETURN_NULL();}}8、包装第三方库SEARCH_PATH="/usr/local /usr" #lib搜索的目录SEARCH_FOR="/include/curl/curl.h" #lib头文件的路径if test -r $PHP_LIBS/$SEARCH_FOR; thenLIBS_DIR=$PHP_LIBSelse # search default path listAC_MSG_CHECKING([for libs files in default path])for i in $SEARCH_PATH ; doif test -r $i/$SEARCH_FOR; thenLIBS_DIR=$i#搜索到的lib的路径AC_MSG_RESULT(found in $i)fidonefi/*验证lib是否存在*/if test -z "$LIBS_DIR"; thenAC_MSG_RESULT([not found])AC_MSG_ERROR([Please reinstall the libs distribution])fi/*编译的时候添加lib的include目录, -I/usr/include*/PHP_ADD_INCLUDE($LIBS_DIR/include)LIBNAME=curl#lib名称 LIBSYMBOL=curl_version #lib的一个函数,用来PHP_CHECK_LIBRARY验证lib/*验证lib*/PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, [PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $LIBS_DIR/$PHP_LIBDIR, LIBS_SHARED_LIBADD) #编译的时候链接lib, -llibcurlAC_DEFINE(HAVE_LIBSLIB,1,[ ])],[AC_MSG_ERROR([wrong libs lib version or lib not found])],[-L$LIBS_DIR/$PHP_LIBDIR -lm]) PHP_SUBST(LIBS_SHARED_LIBADD)9、用于返回的宏
function hello_array_strings($arr) {if (!is_array($arr)) return NULL;printf("The array passed contains %d elements ", count($arr));foreach($arr as $data) {if (is_string($data)) echo "$data ";}}PHP内核实现PHP_FUNCTION(hello_array_strings){zval *arr, **data;HashTable *arr_hash;HashPosition pointer;int array_count;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) {RETURN_NULL();}arr_hash = Z_ARRVAL_P(arr);array_count = zend_hash_num_elements(arr_hash);php_printf("The array passed contains %d elements ", array_count);for(zend_hash_internal_pointer_reset_ex(arr_hash, &pointer); zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS; zend_hash_move_forward_ex(arr_hash, &pointer)) {if (Z_TYPE_PP(data) == IS_STRING) {PHPWRITE(Z_STRVAL_PP(data), Z_STRLEN_PP(data));php_printf(" ");}}RETURN_TRUE;}以上所述就是本文给大家介绍的PHP扩展开发教程,希望大家喜欢。