国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網站 > 建站經驗 > 正文

PHP擴展開發教程(總結)

2024-04-25 20:16:36
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了PHP擴展開發教程的相關資料,需要的朋友可以參考下

PHP是一種解釋型的語言,對于用戶而言,我們精心的控制內存意味著easier prototyping和更少的崩潰!當我們深入到內核之后,所有的安全防線都已經被越過,最終還是要依賴于真正有責任心的軟件工程師來保證系統的穩定運行。

1、線程安全宏定義

在TSRM/TSRM.h文件中有如下定義

  1. #define TSRMLS_FETCH()       void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL) 
  2. #define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx 
  3. #define TSRMLS_SET_CTX(ctx)   ctx = (void ***) tsrm_ls 
  4. #define TSRMG(id, type, element)   (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element) 
  5. #define TSRMLS_D   void ***tsrm_ls 
  6. #define TSRMLS_DC  , TSRMLS_D 
  7. #define TSRMLS_C   tsrm_ls 
  8. #define TSRMLS_CC  , TSRMLS_C 

在ext/xsl/php_xsl.h有這么一段話

  1. /* In every utility function you add that needs to use variables.                                                                    
  2.    in php_xsl_globals, call TSRM_FETCH(); after declaring other. 
  3.    variables used by that function, or better yet, pass in TSRMLS_CC 
  4.    after the last function argument and declare your utility function 
  5.    with TSRMLS_DC after the last declared argument.  Always refer to 
  6.    the globals in your function as XSL_G(variable).  You are. 
  7.    encouraged to rename these macros something shorter, see 
  8.    examples in any other php module directory. 
  9. */ 

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

  1. PHP_GINIT_FUNCTION(test) 
  2.   /** 初始化全局變量 */ 
  3. //對應的C代碼 
  4. void zm_globals_ctor_test (zend_test_globals *test_globals TSRMLS_DC) 
  5.   /** 初始化全局變量 */ 
  6. //在線程退出時,需要將之前自己申請的資源釋放時,可以使用 PHP_GSHUTDOWN_FUNCTION來注冊析構函數。 
  7. PHP_GSHUTDOWN_FUNCTION(test) 
  8.   /** 清除全局變量 */ 
  9. //對應的C代碼 
  10. void zm_globals_dtor_test (zend_test_globals *test_globals TSRMLS_DC) 
  11.   /** 清除全局變量 */ 

這里有一段代碼,可以測試一下

  1. int minit_time; 
  2. PHP_MINIT_FUNCTION(test) 
  3.   minit_time = time(NULL); 
  4.   return SUCCESS; 
  5. PHP_MSHUTDOWN_FUNCTION(test) 
  6.   FILE *fp=fopen("mshutdown.txt","a+"); 
  7.   fprintf(fp,"%ld/n",time(NULL)); 
  8.   fclose(fp); 
  9.   return SUCCESS; 
  10. int rinit_time; 
  11. PHP_RINIT_FUNCTION(test) 
  12.   rinit_time = time(NULL); 
  13.   return SUCCESS; 
  14. PHP_RSHUTDOWN_FUNCTION(test) 
  15.   FILE *fp=fopen("rshutdown.txt","a+"); 
  16.   fprintf(fp,"%ld/n",time(NULL)); 
  17.   fclose(fp); 
  18.   return SUCCESS; 
  19. PHP_MINFO_FUNCTION(test) 
  20.   php_info_print_table_start(); 
  21.   php_info_print_table_header(, "module info""enabled"); 
  22.   php_info_print_table_end(); 
  23.   /* Remove comments if you have entries in php.ini 
  24.   DISPLAY_INI_ENTRIES(); 
  25.   */ 
  26. PHP_FUNCTION(test) 
  27.   php_printf("%d",time_of_minit); 
  28.   php_printf("%d",time_of_rinit); 
  29.   return

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文件中

  1. typedef struct _sapi_globals_struct { 
  2.   void *server_context; 
  3.   sapi_request_info request_info; 
  4.   sapi_headers_struct sapi_headers; 
  5.   int read_post_bytes; 
  6.   unsigned char headers_sent; 
  7.   struct stat global_stat; 
  8.   char *default_mimetype; 
  9.   char *default_charset; 
  10.   HashTable *rfc1867_uploaded_files; 
  11.   long post_max_size; 
  12.   int options; 
  13.   zend_bool sapi_started; 
  14.   double global_request_time; 
  15.   HashTable known_post_content_types; 
  16.   zval *callback_func; 
  17.   zend_fcall_info_cache fci_cache; 
  18.   zend_bool callback_run; 
  19. } sapi_globals_struct; 

看一下SG的定義

  1. BEGIN_EXTERN_C() 
  2. #ifdef ZTS 
  3. # define SG(v) TSRMG(sapi_globals_id, sapi_globals_struct *, v) 
  4. SAPI_API extern int sapi_globals_id; 
  5. #else 
  6. # define SG(v) (sapi_globals.v) 
  7. extern SAPI_API sapi_globals_struct sapi_globals; 
  8. #endif 
  9. SAPI_API void sapi_startup(sapi_module_struct *sf); 
  10. SAPI_API void sapi_shutdown(void); 
  11. SAPI_API void sapi_activate(TSRMLS_D); 
  12. SAPI_API void sapi_deactivate(TSRMLS_D); 
  13. SAPI_API void sapi_initialize_empty_request(TSRMLS_D); 
  14. END_EXTERN_C() 

成員都在sapi_globals_struct這里了

那么我么可以這樣調用

SG(default_mimetype)

SG(request_info).request_uri

可以感受一下這么一段代碼

  1. static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) 
  2.   char buf[SAPI_CGI_MAX_HEADER_LENGTH]; 
  3.   sapi_header_struct *h; 
  4.   zend_llist_position pos; 
  5.   long rfc2616_headers = 0; 
  6.   if(SG(request_info).no_headers == 1) { 
  7.     return SAPI_HEADER_SENT_SUCCESSFULLY; 
  8.   } 
  9.   if (SG(sapi_headers).http_response_code != 200) { 
  10.     int len; 
  11.     len = sprintf(buf, "Status: %d/r/n", SG(sapi_headers).http_response_code); 
  12.     PHPWRITE_H(buf, len); 
  13.   } 
  14.   if (SG(sapi_headers).send_default_content_type) { 
  15.     char *hd; 
  16.     hd = sapi_get_default_content_type(TSRMLS_C); 
  17.     PHPWRITE_H("Content-type:", sizeof("Content-type: ")-1); 
  18.     PHPWRITE_H(hd, strlen(hd)); 
  19.     PHPWRITE_H("/r/n", 2); 
  20.     efree(hd); 
  21.   } 
  22.   h = zend_llist_get_first_ex(&sapi_headers->headers, &pos); 
  23.   while (h) { 
  24.     PHPWRITE_H(h->header, h->header_len); 
  25.     PHPWRITE_H("/r/n", 2); 
  26.     h = zend_llist_get_next_ex(&sapi_headers->headers, &pos); 
  27.   } 
  28.   PHPWRITE_H("/r/n", 2); 
  29.   return SAPI_HEADER_SENT_SUCCESSFULLY; 

2、EG  Executor Globals

EG獲取的是struct _zend_execution_globals結構體中的數據

  1. struct _zend_execution_globals { 
  2.  ... 
  3.  HashTable symbol_table;  /* 全局作用域,如果沒有進入函數內部,全局=活動 */ 
  4.  HashTable *active_symbol_table; /* 活動作用域,當前作用域 */ 
  5.  ... 

通常,使用EG(symbol_table)獲取的是全局作用域中的符號表,使用EG(active_symbol_table)獲取的是當前作用域下的符號表

例如 來定義$foo = 'bar'

  1. zval *fooval; 
  2.  
  3. MAKE_STD_ZVAL(fooval); 
  4. ZVAL_STRING(fooval, "bar", 1); 
  5. ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", fooval); 

或者從符號表中查找$foo

  1. zval **fooval; 
  2. if(zend_hash_find(&EG(symbol_table), "foo", sizeof("foo"), (void **)&fooval) == SUCCESS) { 
  3.     RETURN_STRINGL(Z_STRVAL_PP(fooval), Z_STRLEN_PP(fooval)); 
  4. else { 
  5.     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、獲取變量的類型和值

  1. #define Z_TYPE(zval)        (zval).type 
  2. #define Z_TYPE_P(zval_p)    Z_TYPE(*zval_p) 
  3. #define Z_TYPE_PP(zval_pp)  Z_TYPE(**zval_pp) 

比如獲取一個變量的類型

  1. void describe_zval(zval *foo) 
  2.   if ( Z_TYPE_P(foo) == IS_NULL ) 
  3.   { 
  4.     php_printf("這個變量的數據類型是: NULL"); 
  5.   } 
  6.   else 
  7.   { 
  8.     php_printf("這個變量的數據類型不是NULL,這種數據類型對應的數字是: %d", Z_TYPE_P(foo)); 
  9.   } 

有這么幾種類型

  1. #define IS_NULL     0 
  2. #define IS_LONG     1 
  3. #define IS_DOUBLE   2 
  4. #define IS_BOOL     3 
  5. #define IS_ARRAY    4 
  6. #define IS_OBJECT   5 
  7. #define IS_STRING   6 
  8. #define IS_RESOURCE 7 
  9. #define IS_CONSTANT 8 
  10. #define IS_CONSTANT_ARRAY   9 
  11. #define IS_CALLABLE 10 

php_printf()函數是內核對printf()函數的一層封裝,我們可以像使用printf()函數那樣使用它,以一個P結尾的宏的參數大多是*zval型變量。 此外獲取變量類型的宏還有兩個,分別是Z_TYPE和Z_TYPE_PP,前者的參數是zval型,而后者的參數則是**zval

比如gettype函數的實現

  1. //開始定義php語言中的函數gettype 
  2. PHP_FUNCTION(gettype
  3.   //arg間接指向調用gettype函數時所傳遞的參數。是一個zval**結構 
  4.   //所以我們要對他使用__PP后綴的宏。 
  5.   zval **arg; 
  6.   //這個if的操作主要是讓arg指向參數~ 
  7.   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) { 
  8.     return
  9.   } 
  10.   //調用Z_TYPE_PP宏來獲取arg指向zval的類型。 
  11.   //然后是一個switch結構,RETVAL_STRING宏代表這gettype函數返回的字符串類型的值 
  12.   switch (Z_TYPE_PP(arg)) { 
  13.     case IS_NULL
  14.       RETVAL_STRING("NULL", 1); 
  15.       break
  16.     case IS_BOOL
  17.       RETVAL_STRING("boolean", 1); 
  18.       break
  19.     case IS_LONG
  20.       RETVAL_STRING("integer", 1); 
  21.       break
  22.     case IS_DOUBLE
  23.       RETVAL_STRING("double", 1); 
  24.       break
  25.     case IS_STRING
  26.       RETVAL_STRING("string", 1); 
  27.       break
  28.     case IS_ARRAY
  29.       RETVAL_STRING("array", 1); 
  30.       break
  31.     case IS_OBJECT
  32.       RETVAL_STRING("object", 1); 
  33.       break
  34.     case IS_RESOURCE
  35.       { 
  36.         char *type_name; 
  37.         type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(arg) TSRMLS_CC); 
  38.         if (type_name) { 
  39.           RETVAL_STRING("resource", 1); 
  40.           break
  41.         } 
  42.       } 
  43.     default
  44.       RETVAL_STRING("unknown type", 1); 
  45.   } 

獲取變量的值,有這么多宏來獲取

  1. Long 
  2.  
  3. Boolean 
  4.  
  5. Double 
  6.  
  7. String value 
  8.  
  9. String length 
  10.  
  11. Z_LVAL( ) 
  12. Z_BVAL( ) 
  13. Z_DVAL( ) 
  14. Z_STRVAL( ) 
  15. Z_STRLEN( ) 
  16. Z_LVAL_P( ) 
  17. Z_BVAL_P( ) 
  18. Z_DVAL_P( ) 
  19. Z_STRVAL_P( ) 
  20. Z_STRLEN_P( ) 
  21. Z_LVAL_PP( ) 
  22. Z_BVAL_PP( ) 
  23. Z_DVAL_PP( ) 
  24. Z_STRVAL_PP( ) 
  25. Z_STRLEN_PP( ) 
  26. HashTable 
  27.  
  28. Object 
  29.  
  30. Object properties 
  31.  
  32. Object class entry 
  33.  
  34. Resource value 
  35.  
  36. Z_ARRVAL( ) 
  37. Z_OBJ( ) 
  38. Z_OBJPROP( ) 
  39. Z_OBJCE( ) 
  40. Z_RESVAL( ) 
  41. Z_ARRVAL_P( ) 
  42. Z_OBJ_P( ) 
  43. Z_OBJPROP_P( ) 
  44. Z_OBJCE_P( ) 
  45. Z_RESVAL_P( ) 
  46. Z_ARRVAL_PP( ) 
  47. Z_OBJ_PP( ) 
  48. Z_OBJPROP_PP( ) 
  49. Z_OBJCE_PP( ) 
  50. Z_RESVAL_PP( ) 

rot13函數的實現

  1. PHP_FUNCTION(rot13) 
  2.  zval **arg; 
  3.  char *ch, cap; 
  4.  int i; 
  5.     
  6.  if (ZEND_NUM_ARGS( ) != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) { 
  7.    WRONG_PARAM_COUNT; 
  8.  } 
  9.  *return_value = **arg; 
  10.  zval_copy_ctor(return_value); 
  11.  convert_to_string(return_value); 
  12.     
  13.  for(i=0, ch=return_value->value.str.val; 
  14.    i<return_value->value.str.len; i++, ch++) { 
  15.     cap = *ch & 32; 
  16.     *ch &= ~cap; 
  17.     *ch = ((*ch>='A') && (*ch<='Z') ? ((*ch-'A'+13) % 26 + 'A') : *ch) | cap; 
  18.   } 

要獲取變量的值,也應該使用Zend定義的宏進行訪問。對于簡單的標量數據類型、Boolean,long,double, 使用Z_BVAL, Z_LVAL, Z_DVAL

  1. void display_values(zval boolzv, zval *longpzv, zval **doubleppzv) 
  2.  if (Z_TYPE(boolzv) == IS_BOOL) { 
  3.   php_printf("The value of the boolean is : %s/n", Z_BVAL(boolzv) ? "true" : "false"); 
  4.  } 
  5.  if(Z_TYPE_P(longpzv) == IS_LONG) { 
  6.   php_printf("The value of the long is: %ld/n", Z_LVAL_P(longpzv)); 
  7.  } 
  8.  if(Z_TYPE_PP(doubleppzv) == IS_DOUBLE) { 
  9.   php_printf("The value of the double is : %f/n", Z_DVAL_PP(doubleppzv)); 
  10.  } 

對于字符串類型,因為它含有兩個字段char * (Z_STRVAL) 和 int (Z_STRLEN),因此需要用兩個宏來進行取值,因為需要二進制安全的輸出這個字符串

  1. void display_string(zval *zstr) 
  2.  if (Z_TYPE_P(zstr) != IS_STRING) { 
  3.   php_printf("The wronng datatype was passed!/n"); 
  4.   return ; 
  5.  } 
  6.  PHPWRITE(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr)); 

因為數組在zval中是以HashTable形式存在的,因此使用Z_ARRVAL()進行訪問

  1. void display_zval(zval *value) 
  2.   switch (Z_TYPE_P(value)) { 
  3.     case IS_NULL
  4.       /* 如果是NULL,則不輸出任何東西 */ 
  5.       break
  6.    
  7.     case IS_BOOL
  8.       /* 如果是bool類型,并且true,則輸出1,否則什么也不干 */ 
  9.       if (Z_BVAL_P(value)) { 
  10.         php_printf("1"); 
  11.       } 
  12.       break
  13.     case IS_LONG
  14.       /* 如果是long整型,則輸出數字形式 */ 
  15.       php_printf("%ld", Z_LVAL_P(value)); 
  16.       break
  17.     case IS_DOUBLE
  18.       /* 如果是double型,則輸出浮點數 */ 
  19.       php_printf("%f", Z_DVAL_P(value)); 
  20.       break
  21.     case IS_STRING
  22.       /* 如果是string型,則二進制安全的輸出這個字符串 */ 
  23.       PHPWRITE(Z_STRVAL_P(value), Z_STRLEN_P(value)); 
  24.       break
  25.     case IS_RESOURCE
  26.       /* 如果是資源,則輸出Resource #10 格式的東東 */ 
  27.       php_printf("Resource #%ld", Z_RESVAL_P(value)); 
  28.       break
  29.     case IS_ARRAY
  30.       /* 如果是Array,則輸出Array5個字母! */ 
  31.       php_printf("Array"); 
  32.       break
  33.     case IS_OBJECT
  34.       php_printf("Object"); 
  35.       break
  36.     default
  37.       /* Should never happen in practice, 
  38.        * but it's dangerous to make assumptions 
  39.        */ 
  40.        php_printf("Unknown"); 
  41.        break
  42.   } 

一些類型轉換函數

  1. ZEND_API void convert_to_long(zval *op); 
  2. ZEND_API void convert_to_double(zval *op); 
  3. ZEND_API void convert_to_null(zval *op); 
  4. ZEND_API void convert_to_boolean(zval *op); 
  5. ZEND_API void convert_to_array(zval *op); 
  6. ZEND_API void convert_to_object(zval *op); 
  7. ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC); 

6、常量的實例化

我們可以這樣實例化

  1. PHP_MINIT_FUNCTION(consts) //模塊初始化時定義常量 
  2.   REGISTER_LONG_CONSTANT("CONSTS_MEANING_OF_LIFE", 42, CONST_CS | CONST_PERSISTENT); 
  3.   REGISTER_DOUBLE_CONSTANT("CONSTS_PI", 3.1415926, CONST_PERSISTENT); 
  4.   REGISTER_STRING_CONSTANT("CONSTS_NAME""leon", CONST_CS|CONST_PERSISTENT); 
  5. PHP_RINIT_FUNCTION(consts) //每次請求時定義常量 
  6.   char buffer[40]; 
  7.   srand((int)time(NULL)); 
  8.   snprintf(buffer, sizeof(buffer), "%d", rand()); 
  9.   REGISTER_STRING_CONSTANT("CONSTS_RAND", estrdup(buffer), CONST_CS); 
  10.   return SUCCESS; 

常見的宏

  1. /*注冊LONG類型常量*/ 
  2. #define REGISTER_LONG_CONSTANT(name, lval, flags)  zend_register_long_constant((name), sizeof(name), (lval), (flags), module_number TSRMLS_CC) 
  3.  /*注冊double類型常量*/ 
  4. #define REGISTER_DOUBLE_CONSTANT(name, dval, flags)  zend_register_double_constant((name), sizeof(name), (dval), (flags), module_number TSRMLS_CC) 
  5.  
  6.  
  7. /*注冊STRING類型常量*/ 
  8. #define REGISTER_STRING_CONSTANT(name, str, flags)  zend_register_string_constant((name), sizeof(name), (str), (flags), module_number TSRMLS_CC) 
  9. /*注冊STRING類型常量*/ 
  10. #define REGISTER_STRINGL_CONSTANT(name, str, len, flags)  zend_register_stringl_constant((name), sizeof(name), (str), (len), (flags), module_number TSRMLS_CC) 

7、全局變量

  1. #php-fpm 生成 POST|GET|COOKIE|SERVER|ENV|REQUEST|FILES全局變量的流程 
  2. php_cgi_startup() -> php_module_startup() -> php_startup_auto_globals() -> 保存變量到symbol_table符號表 
  3. php_cgi_startup()在 fpm/fpm/fpm_main.c中定義 
  4. php_module_startup() 在main/main.c中定義 
  5. php_startup_auto_globals() 在main/php_variables.h中定義 
  6. zend_hash_update(&EG(symbol_table), "_GET", sizeof("_GET") + 1, &vars, sizeof(zval *), NULL); 
  7. /* 讀取$_SERVER變量 */ 
  8. static PHP_FUNCTION(print_server_vars) { 
  9.   zval **val; 
  10.   if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) { 
  11.     RETURN_ZVAL(*val, 1, 0); 
  12.   }else
  13.    RETURN_FALSE; 
  14.   } 
  15. /* 讀取$_SERVER[$name] */ 
  16. ZEND_BEGIN_ARG_INFO(print_server_var_arginfo, 0) 
  17.   ZEND_ARG_INFO(0, "name"
  18. ZEND_END_ARG_INFO() 
  19. static PHP_FUNCTION(print_server_var) { 
  20.   char *name; 
  21.   int name_len; 
  22.   zval **val; 
  23.   HashTable *ht_vars = NULL; 
  24.   HashPosition pos; 
  25.   zval **ret_val; 
  26.   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &name_len) == FAILURE) { 
  27.     RETURN_NULL(); 
  28.   } 
  29.   if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&val) == SUCCESS) { 
  30.     ht_vars = Z_ARRVAL_PP(val); 
  31.     //此處需傳入大于name長度+1的值,因為字符串值后面需要'/0' 
  32.     if (zend_hash_find(ht_vars, name, name_len+1, (void **)&ret_val) == SUCCESS) {       RETURN_STRING(Z_STRVAL_PP(ret_val), 0); 
  33.     }else
  34.       RETURN_NULL(); 
  35.     } 
  36.   }else
  37.     RETURN_NULL(); 
  38.   } 

8、包裝第三方庫

配置(config.m4)

  1. SEARCH_PATH="/usr/local /usr"   #lib搜索的目錄 
  2. SEARCH_FOR="/include/curl/curl.h" #lib頭文件的路徑 
  3. if test -r $PHP_LIBS/$SEARCH_FOR; then 
  4.   LIBS_DIR=$PHP_LIBS 
  5. else # search default path list 
  6.   AC_MSG_CHECKING([for libs files in default path]) 
  7.   for i in $SEARCH_PATH ; do 
  8.     if test -r $i/$SEARCH_FOR; then 
  9.       LIBS_DIR=$i        #搜索到的lib的路徑 
  10.       AC_MSG_RESULT(found in $i
  11.     fi 
  12.   done 
  13. fi 
  14. /*驗證lib是否存在*/ 
  15. if test -z "$LIBS_DIR"; then 
  16.   AC_MSG_RESULT([not found]) 
  17.   AC_MSG_ERROR([Please reinstall the libs distribution]) 
  18. fi 
  19. /*編譯的時候添加lib的include目錄, -I/usr/include*/ 
  20. PHP_ADD_INCLUDE($LIBS_DIR/include
  21. LIBNAME=curl      #lib名稱  
  22. LIBSYMBOL=curl_version #lib的一個函數,用來PHP_CHECK_LIBRARY驗證lib 
  23. /*驗證lib*/ 
  24. PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,  
  25.   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME$LIBS_DIR/$PHP_LIBDIR, LIBS_SHARED_LIBADD) #編譯的時候鏈接lib, -llibcurl 
  26.   AC_DEFINE(HAVE_LIBSLIB,1,[ ]) 
  27. ],[ 
  28.   AC_MSG_ERROR([wrong libs lib version or lib not found]) 
  29. ],[ 
  30.   -L$LIBS_DIR/$PHP_LIBDIR -lm 
  31. ])  
  32. PHP_SUBST(LIBS_SHARED_LIBADD) 

9、用于返回的宏

  1. //這些宏都定義在Zend/zend_API.h文件里 
  2. #define RETVAL_RESOURCE(l)              ZVAL_RESOURCE(return_value, l) 
  3. #define RETVAL_BOOL(b)                  ZVAL_BOOL(return_value, b) 
  4. #define RETVAL_NULL()                   ZVAL_NULL(return_value) 
  5. #define RETVAL_LONG(l)                  ZVAL_LONG(return_value, l) 
  6. #define RETVAL_DOUBLE(d)                ZVAL_DOUBLE(return_value, d) 
  7. #define RETVAL_STRING(s, duplicate)         ZVAL_STRING(return_value, s, duplicate) 
  8. #define RETVAL_STRINGL(s, l, duplicate)     ZVAL_STRINGL(return_value, s, l, duplicate) 
  9. #define RETVAL_EMPTY_STRING()           ZVAL_EMPTY_STRING(return_value) 
  10. #define RETVAL_ZVAL(zv, copy, dtor)     ZVAL_ZVAL(return_value, zv, copy, dtor) 
  11. #define RETVAL_FALSE                    ZVAL_BOOL(return_value, 0) 
  12. #define RETVAL_TRUE                     ZVAL_BOOL(return_value, 1) 
  13. #define RETURN_RESOURCE(l)              { RETVAL_RESOURCE(l); return; } 
  14. #define RETURN_BOOL(b)                  { RETVAL_BOOL(b); return; } 
  15. #define RETURN_NULL()                   { RETVAL_NULL(); return;} 
  16. #define RETURN_LONG(l)                  { RETVAL_LONG(l); return; } 
  17. #define RETURN_DOUBLE(d)                { RETVAL_DOUBLE(d); return; } 
  18. #define RETURN_STRING(s, duplicate)     { RETVAL_STRING(s, duplicate); return; } 
  19. #define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; } 
  20. #define RETURN_EMPTY_STRING()           { RETVAL_EMPTY_STRING(); return; } 
  21. #define RETURN_ZVAL(zv, copy, dtor)     { RETVAL_ZVAL(zv, copy, dtor); return; } 
  22. #define RETURN_FALSE                    { RETVAL_FALSE; return; } 
  23. #define RETURN_TRUE                     { RETVAL_TRUE; return; } 

其實,除了這些標量類型,還有很多php語言中的復合類型我們需要在函數中返回,如數組和對象,我們可以通過RETVAL_ZVAL與RETURN_ZVAL來操作它們

10、hashTable的遍歷函數

  1. //基于long key的操作函數 
  2. zval *v3; 
  3. MAKE_STD_ZVAL(v3); 
  4. ZVAL_STRING(v3, "value3", 1); 
  5. zend_hash_index_update(names, 0, &v3, sizeof(zval *), NULL);//按數字索引鍵更新HashTable元素的值 
  6. zval **v4; 
  7. zend_hash_index_find(names, 1, &v4); //按數字索引獲取HashTable元素的值 
  8. php_printf("v4 : "); 
  9. PHPWRITE(Z_STRVAL_PP(v4), Z_STRLEN_PP(v4)); 
  10. php_printf("/n"); 
  11. ulong idx; 
  12. idx = zend_hash_index_exists(names, 10);//按數字索引查找HashTable,如果找到返回 1, 反之則返回 0 
  13. zend_hash_index_del(names, 2);    //按數字索引刪除HashTable元素 
  14. //hashTable的遍歷函數 
  15. zend_hash_internal_pointer_reset(names); //初始化hash指針 
  16. zend_hash_internal_pointer_reset_ex(names, &pos);//初始化hash指針,并付值給pos 
  17. zend_hash_get_current_data(names, (void**) &val); //獲取當前hash存儲值,data should be cast to void**, ie: (void**) &data 
  18. zend_hash_get_current_data_ex(names, (void**) &val, &pos) == SUCCESS; //獲取當前hash存儲值 
  19. zend_hash_get_current_key(names, &key, &klen, &index, 0) == HASH_KEY_IS_LONG 
  20. zend_hash_get_current_key_ex(names, &key, &klen, &index, 0, &pos) == HASH_KEY_IS_LONG; //讀取hashtable當前的KEY,返回值會有兩種 HASH_KEY_IS_LONG | HASH_KEY_IS_STRING ,分別對應array("value"),array("key"=>"value")兩種hashtable 
  21. zend_hash_move_forward(names); 
  22. zend_hash_move_forward_ex(names, &pos); //hash指針移至下一位 
  23. //HashTable長度 
  24. php_printf("%*carray(%d) {/n", depth * 2, ' ', zend_hash_num_elements(Z_ARRVAL_P(zv)) 

一個簡單的函數

  1. function hello_array_strings($arr) { 
  2.   if (!is_array($arr)) return NULL; 
  3.   printf("The array passed contains %d elements "count($arr)); 
  4.   foreach($arr as $data) { 
  5.     if (is_string($data)) echo "$data "
  6.   } 

PHP內核實現

  1. PHP_FUNCTION(hello_array_strings) 
  2.   zval *arr, **data; 
  3.   HashTable *arr_hash; 
  4.   HashPosition pointer; 
  5.   int array_count; 
  6.   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) { 
  7.     RETURN_NULL(); 
  8.   } 
  9.   arr_hash = Z_ARRVAL_P(arr); 
  10.   array_count = zend_hash_num_elements(arr_hash); 
  11.   php_printf("The array passed contains %d elements ", array_count); 
  12.   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)) { 
  13.     if (Z_TYPE_PP(data) == IS_STRING) { 
  14.       PHPWRITE(Z_STRVAL_PP(data), Z_STRLEN_PP(data)); 
  15.       php_printf(" "); 
  16.     } 
  17.   } 
  18.   RETURN_TRUE; 

以上所述就是本文給大家介紹的PHP擴展開發教程,希望大家喜歡。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 江安县| 大丰市| 宜阳县| 霍林郭勒市| 曲松县| 宕昌县| 新泰市| 藁城市| 礼泉县| 大足县| 腾冲县| 永州市| 额济纳旗| 新乡县| 三河市| 柘城县| 信阳市| 招远市| 城固县| 大渡口区| 连南| 孙吴县| 孝感市| 东山县| 和顺县| 道孚县| 唐海县| 报价| 大城县| 洛扎县| 天镇县| 霸州市| 南丹县| 慈溪市| 石柱| 达拉特旗| 浦江县| 长治市| 乡宁县| 阳东县| 乐昌市|