日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

[转]用C/C++扩展PHP详解

發(fā)布時(shí)間:2023/12/31 php 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转]用C/C++扩展PHP详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文:http://www.imsiren.com/archives/547

一個(gè)簡(jiǎn)單的擴(kuò)展模塊
PHP非常容易擴(kuò)展,因?yàn)樗峁┝宋覀兿胗玫乃蠥PI.
如果要新建一個(gè)擴(kuò)展,需要在PHP源碼中執(zhí)行ext_skel
位置 PHP源碼目錄/ext/ext_skel
它有幾個(gè)參數(shù)
–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
如果我們要建一個(gè) 擴(kuò)展名稱為siren的模塊,那么我們只要執(zhí)行
ext_skel –extname=siren 它就會(huì)在 ext/目錄下生成以 模塊名稱為名的文件夾.而且還會(huì)創(chuàng)建一些文件:
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 ,這樣是非常浪費(fèi)時(shí)間的,所以我把它編譯為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, for siren support,
Make sure that the comment is aligned:
[ --with-siren Include siren support])
這樣在編譯PHP的時(shí)候 –with-siren就可以加載此模塊,也可以在php.ini中extension 模塊.
在ext/siren目錄下有一個(gè)siren.c文件
它提供了一個(gè)默認(rèn)函數(shù)

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, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "siren", arg); ????????RETURN_STRINGL(strg, len, 0); }

如果看過(guò) 我之前的文章,你肯定明白 如果不知道 那就看看這篇文章
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
這樣 就會(huì)在/usr/local/php53/lib/php/extensions/no-debug-non-zts-20090626/目錄下生成一個(gè)siren.so文件
這樣 一個(gè)簡(jiǎn)單的擴(kuò)展模塊就完成了..我們?cè)赑HP.INI里面開(kāi)啟此模塊
重啟apache/nginx, 這樣 在php文件里 就可以 執(zhí)行 confirm_siren_compiled函數(shù)了.

下面我們就詳細(xì)講解一下里面的東西
首先是 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);?? /*這是一個(gè)測(cè)試函數(shù)*/ /* 如果要聲明全局變量,就在這里聲明???? 如果要啟用 全局變量,那還要把siren.c中的ZEND_DECLARE_MODULE_GLOBALS(siren)注釋去掉 ZEND_BEGIN_MODULE_GLOBALS(siren) ????????long? global_value; ????????char *global_string; ZEND_END_MODULE_GLOBALS(siren) */ /* In every utility function you add that needs to use variables ???in php_siren_globals, call TSRMLS_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 SIREN_G(variable).? You are ???encouraged to rename these macros something shorter, see ???examples in any other php module directory. */ #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 */

上面有幾個(gè) PHP_*的函數(shù),他們的作用如下

PHP_MINIT_FUNCTION() 當(dāng)PHP被裝載時(shí),模塊啟動(dòng)函數(shù)即被Zend引擎調(diào)用,這里可以做一些初始化操作
PHP_MSHUTDOWN_FUNCTION() 當(dāng)PHP完全關(guān)閉時(shí),Zend引擎調(diào)用的函數(shù),
PHP_RINIT_FUNCTION() 在每次PHP請(qǐng)求開(kāi)始,請(qǐng)求前啟動(dòng)函數(shù)被調(diào)用。通常用于管理請(qǐng)求前邏輯。
PHP_RSHUTDOWN_FUNCTION() 在每次PHP請(qǐng)求結(jié)束后,請(qǐng)求前關(guān)閉函數(shù)被調(diào)用。經(jīng)常應(yīng)用在清理請(qǐng)求前啟動(dòng)函數(shù)的邏輯。
PHP_MINFO_FUNCTION() 調(diào)用phpinfo()時(shí)模塊信息函數(shù)被呼叫,從而打印出模塊信息。
這些函數(shù)的代碼都定義在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" /* 如果php_siren.h中開(kāi)啟了全局變量,那就去掉注釋 ZEND_DECLARE_MODULE_GLOBALS(siren) */ /* True global resources - no need for thread safety here */ static int le_siren; /* {{{ siren_functions[] ?* ?* Every user visible function must have an entry in siren_functions[]. ?*/ const zend_function_entry siren_functions[] = { ????????PHP_FE(confirm_siren_compiled,? NULL)?????????? /* For testing, remove later. */ ????????PHP_FE_END????? /* Must be the last line in siren_functions[] */ }; /* }}} */ /* {{{ siren_module_entry ?*/ 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),?????????????? /* Replace with NULL if there's nothing to do at request start */ ????????PHP_RSHUTDOWN(siren),?? /* Replace with NULL if there's nothing to do at request end */ ????????PHP_MINFO(siren), #if ZEND_MODULE_API_NO >= 20010901 ????????"0.1", /* Replace with version number for your extension */ #endif ????????STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_SIREN ZEND_GET_MODULE(siren) #endif /* {{{ PHP_INI ?*/ /* Remove comments and fill if you need to have entries in php.ini PHP_INI_BEGIN() ????STD_PHP_INI_ENTRY("siren.global_value",????? "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_siren_globals, siren_globals) ????STD_PHP_INI_ENTRY("siren.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_siren_globals, siren_globals) PHP_INI_END() */ /* }}} */ /* {{{ php_siren_init_globals ?*/ /* Uncomment this function if you have INI entries static void php_siren_init_globals(zend_siren_globals *siren_globals) { ????????siren_globals->global_value = 0; ????????siren_globals->global_string = NULL; } */ /* }}} */ /* {{{ PHP_MINIT_FUNCTION ?*/ PHP_MINIT_FUNCTION(siren) { ????????/* If you have INI entries, uncomment these lines ????????REGISTER_INI_ENTRIES(); ????????*/ ????????return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION ?*/ PHP_MSHUTDOWN_FUNCTION(siren) { ????????/* uncomment this line if you have INI entries ????????UNREGISTER_INI_ENTRIES(); ????????*/ ????????return SUCCESS; } /* }}} */ /* Remove if there's nothing to do at request start */ /* {{{ PHP_RINIT_FUNCTION ?*/ PHP_RINIT_FUNCTION(siren) { ????????return SUCCESS; } /* }}} */ /* Remove if there's nothing to do at request end */ /* {{{ PHP_RSHUTDOWN_FUNCTION ?*/ PHP_RSHUTDOWN_FUNCTION(siren) { ????????return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION ?*/ PHP_MINFO_FUNCTION(siren) { ????????php_info_print_table_start(); ????????php_info_print_table_header(2, "siren support", "enabled"); ????????php_info_print_table_end(); ????????/* Remove comments if you have entries in php.ini ????????DISPLAY_INI_ENTRIES(); ????????*/ } /* Every user-visible function in PHP should document itself in the source */ /* {{{ proto string confirm_siren_compiled(string arg) ???Return a string to confirm that the module is compiled in */ 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, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "siren", arg); ????????RETURN_STRINGL(strg, len, 0); } /* }}} */

第21行 zend_function_entry是一個(gè)結(jié)構(gòu)體

1 2 3 4 5 6 7 typedef struct _zend_function_entry { ????????const char *fname; //函數(shù)名稱 ????????void (*handler)(INTERNAL_FUNCTION_PARAMETERS);? //指向?qū)?yīng) C 函數(shù)的句柄 ????????const struct _zend_arg_info *arg_info;//函數(shù)的參數(shù)信息 ????????zend_uint num_args;//參數(shù)個(gè)數(shù) ????????zend_uint flags; } zend_function_entry;
1 2 3 4 const zend_function_entry siren_functions[] = { ????????PHP_FE(confirm_siren_compiled,? NULL)?????????? /* For testing, remove later. */ ????????PHP_FE_END????? /* Must be the last line in siren_functions[] */ };

上面就是定義了一個(gè)函數(shù)數(shù)組
PHP_FE是一個(gè)宏.
等于
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags },
只是做了一些初始化.
PHP_FE_END 等于 { NULL, NULL, NULL, 0, 0 }
用來(lái)結(jié)束數(shù)組

zend_module_entry 是一個(gè)結(jié)構(gòu)體,用來(lái)保存模塊信息

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;? //模塊結(jié)構(gòu)的大小 ????????unsigned int zend_api; ????????unsigned char zend_debug; //是否wie調(diào)試版本 ????????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;? //Zend 函數(shù)塊的指針 指向zend_function_entry結(jié)構(gòu)數(shù)組 ????????int (*module_startup_func)(INIT_FUNC_ARGS);?? //模塊啟動(dòng)函數(shù) ????????int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);??????? //模塊停止函數(shù) ????????int (*request_startup_func)(INIT_FUNC_ARGS);? //php請(qǐng)求開(kāi)始執(zhí)行的函數(shù) ????????int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);//php請(qǐng)求結(jié)束執(zhí)行的函數(shù) ????????void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);//模塊信息函數(shù)。當(dāng)腳本調(diào)用 phpinfo() 函數(shù)時(shí),Zend 便會(huì)遍歷所有已加載的模塊,并調(diào)用它們的這個(gè)函數(shù)。每個(gè)模塊都有機(jī)會(huì)輸出自己的信息。 ????????const char *version;//模塊版本號(hào) ????????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; };

主要字段都在代碼里注釋了
創(chuàng)建一個(gè) zend_module_entry對(duì)象

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, //函數(shù)列表 ,執(zhí)行了上面定義的 zend_function_entry ????????PHP_MINIT(siren), //模塊開(kāi)始執(zhí)行的函數(shù) ????????PHP_MSHUTDOWN(siren),//模塊結(jié)束執(zhí)行的函數(shù) ????????PHP_RINIT(siren),?? //PHP開(kāi)始請(qǐng)求執(zhí)行的函數(shù) ????????PHP_RSHUTDOWN(siren),? //PHP請(qǐng)求結(jié)束執(zhí)行的函數(shù) ????????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
用來(lái)填充 前面四個(gè)參數(shù)
第48行:
只有你的模塊編譯成 動(dòng)態(tài)模塊的時(shí)候才會(huì)被調(diào)用.這個(gè)函數(shù)的作用就是把模塊的信息塊傳遞 給Zend 并通知 Zend 獲取這個(gè)模塊的相關(guān)內(nèi)容
54-57行:
我們?cè)趯?xiě)PHP的時(shí)候,php.ini里面的配置都會(huì)影響我們PHP代碼的執(zhí)行,比如register_global 等.
此處代碼的作用就是獲取php.ini里面的配置信息.

1 STD_PHP_INI_ENTRY("siren.global_value",????? "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_siren_globals, siren_globals)

STD_PHP_INI_ENTRY宏:注冊(cè)php INI的指令:
接受的參數(shù)列表如下
name: php.ini里面的名稱
default_value: //默認(rèn)值,永遠(yuǎn)都是字符串

modifiable: ini可以被改變的地方 值如下
PHP_INI_SYSTEM. 能夠在php.ini或http.conf等系統(tǒng)文件更改
PHP_INI_PERDIR. 能夠在 .htaccess中更改
PHP_INI_USER. 能夠被用戶腳本更改
PHP_INI_ALL. 能夠在所有地方更改

on_modify: 處理INI條目更改的回調(diào)函數(shù)。你不需自己編寫(xiě)處理程序,使用下面提供的函數(shù)。包括:

OnUpdateInt
OnUpdateString
OnUpdateBool
OnUpdateStringUnempty
OnUpdateReal

property_name: 應(yīng)當(dāng)被更新的變量名
struct_type: 變量駐留的結(jié)構(gòu)類型。因?yàn)橥ǔJ褂萌肿兞繖C(jī)制,所以這個(gè)類型自動(dòng)被定義,類似于zend_myfile_globals。
struct_ptr: 全局結(jié)構(gòu)名。如果使用全局變量機(jī)制,該名為myfile_globals。

剩下的東西就是我們上面提到的一些 啟動(dòng)模塊時(shí)執(zhí)行的函數(shù)…
明白了這些,再去寫(xiě)模塊頭就不會(huì)大啦…

總結(jié)

以上是生活随笔為你收集整理的[转]用C/C++扩展PHP详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。