php调用C代码的方法详解
生活随笔
收集整理的這篇文章主要介紹了
php调用C代码的方法详解
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在php程序中需要用到C代碼,應(yīng)該是下面兩種情況:
1 已有C代碼,在php程序中想直接用 2 由于php的性能問題,需要用C來實(shí)現(xiàn)部分功能針對(duì)第一種情況,最合適的方法是用system調(diào)用,把現(xiàn)有C代碼寫成一個(gè)獨(dú)立的程序。參數(shù)通過命令行或者標(biāo)準(zhǔn)輸入傳入,結(jié)果從標(biāo)準(zhǔn)輸出讀出。其次,稍麻煩一點(diǎn)的方法是C代碼寫成一個(gè)daemon,php程序用socket來和它進(jìn)行通訊。
重點(diǎn)講講第二種情況,雖然沿用system調(diào)用的方法也可以,但是想想你的目的是優(yōu)化性能,那么頻繁的起這么多進(jìn)程,當(dāng)然會(huì)讓性能下降。而寫daemon的方法固然可行,可是繁瑣了很多。
我的簡(jiǎn)單測(cè)試,同樣一個(gè)算法,用C來寫比用php效率能提高500倍。而用php擴(kuò)展的方式,也能提高90多倍(其中的性能損失在了參數(shù)傳遞上了吧,我猜)。
所以有些時(shí)候php擴(kuò)展就是我們的最佳選擇了。
這里我著重介紹一下用C寫php擴(kuò)展的方法,而且不需要重新編譯php。
首先,找到一個(gè)php的源碼,php4或者php5版本的都可以,與你目標(biāo)平臺(tái)的php版本沒有關(guān)系。
在源碼的ext目錄下可以找到名為ext_skel的腳本 在這個(gè)目錄下執(zhí)行 #./ext_skel?--extname=hello 這時(shí)生成了一個(gè)目錄 hello,目錄下有幾個(gè)文件,你只需要關(guān)心這三個(gè):config.m4?hello.c php_hello.h
把這個(gè)目錄拷備到任何你希望的地方,cd進(jìn)去,依次執(zhí)行 #phpize #./configure #make 什么也沒發(fā)生,對(duì)吧? 這是因?yàn)槁┝艘徊?#xff0c;打開config.m4,找到下面 dnl If your extension references something external, use with:
... dnl Otherwise use enable:
... 這是讓你選擇你的擴(kuò)展使用with還是enable,我們用with吧。把with那一部分取消注釋。 如果你和我一樣使用vim編輯器,你就會(huì)很容易發(fā)現(xiàn)dnl三個(gè)字母原來是表示注釋的呀(這是因?yàn)関im默認(rèn)帶了各種文件格式的語法著色包)
我們修改了config.m4后,繼續(xù) #phpize #./configure #make 這時(shí),modules下面會(huì)生成hello.so和hello.la文件。一個(gè)是動(dòng)態(tài)庫,一個(gè)是靜態(tài)庫。
你的php擴(kuò)展已經(jīng)做好了,盡管它還沒有實(shí)現(xiàn)你要的功能,我先說說怎么使用這個(gè)擴(kuò)展吧!ext_skel為你生成了一個(gè)hello.php里面有調(diào)用示例,但是那個(gè)例子需要你把hello.so拷貝到php的擴(kuò)展目錄中去,我們只想實(shí)現(xiàn)自己的功能,不想打造山寨版php,改用我下面的方法來加載吧:
- if(!extension_loaded("hello"))?{
- ????????dl_local("hello.so");
- }
- function?dl_local(?$extensionFile?)?{
- ????????//make?sure?that?we?are?ABLE?to?load?libraries
- ????????if(?!(bool)ini_get(?"enable_dl"?)?||?(bool)ini_get(?"safe_mode"?)?)?{
- ????????????????die(?"dh_local():?Loading?extensions?is?not?permitted./n"?);
- ????????}
- ????????//check?to?make?sure?the?file?exists
- ????????if(?!file_exists(dirname(__FILE__)?.?"/".?$extensionFile?)?)?{
- ????????????????die(?"dl_local():?File?'$extensionFile'?does?not?exist./n"?);
- ????????}
- ????????//check?the?file?permissions
- ????????if(?!is_executable(dirname(__FILE__)?.?"/".?$extensionFile?)?)?{
- ????????????????die(?"dl_local():?File?'$extensionFile'?is?not?executable./n"?);
- ????????}
- ????????//we?figure?out?the?path
- ????????$currentDir?=?dirname(__FILE__)?.?"/";
- ????????$currentExtPath?=?ini_get(?"extension_dir"?);
- ????????$subDirs?=?preg_match_all(?""?,?$currentExtPath?,?$matches?);
- ????????unset(?$matches?);
- ????????//lets?make?sure?we?extracted?a?valid?extension?path
- ????????if(?!(bool)$subDirs?)?{
- ????????????????die(?"dl_local():?Could?not?determine?a?valid?extension?path?[extension_dir]./n"?);
- ????????}
- ????????$extPathLastChar?=?strlen(?$currentExtPath?)?-?1;
- ????????if(?$extPathLastChar?==?strrpos(?$currentExtPath?,?"/"?)?)?{
- ????????????????$subDirs--;
- ????????}
- ????????$backDirStr?=?"";?
- ????????for(?$i?=?1;?$i?<=?$subDirs;?$i++?)?{
- ????????????????$backDirStr?.=?"..";
- ????????????????if(?$i?!=?$subDirs?)?{
- ??????????????????$backDirStr?.=?"/";
- ????????????????}
- ????????}
- ????????//construct?the?final?path?to?load
- ????????$finalExtPath?=?$backDirStr?.?$currentDir?.?$extensionFile;
- ????????//now?we?execute?dl()?to?actually?load?the?module
- ????????if(?!dl(?$finalExtPath?)?)?{
- ????????????????die();
- ????????}
- ????????//if?the?module?was?loaded?correctly,?we?must?bow?grab?the?module?name
- ????????$loadedExtensions?=?get_loaded_extensions();
- ????????$thisExtName?=?$loadedExtensions[?sizeof(?$loadedExtensions?)?-?1?];
- ????????//lastly,?we?return?the?extension?name
- ????????return?$thisExtName;
- }//end?dl_local()
隨后一個(gè)讓人關(guān)心的問題是,如何添加函數(shù)、實(shí)現(xiàn)參數(shù)傳遞和返回值
添加函數(shù)步驟如下: php_hello.h: PHP_FUNCTION(confirm_hello_compiled);// 括號(hào)里面填寫函數(shù)名
hello.c zend_function_entry hello_functions[] = { PHP_FE(confirm_hello_compiled, ?NULL) ? ? ? /* 這里添加一行 */ {NULL, NULL, NULL} ?/* Must be the last line in hello_functions[] */ }; PHP_FUNCTION(confirm_hello_compiled)? {// 這里寫函數(shù)體 } 要實(shí)現(xiàn)的函數(shù)原型其實(shí)都一個(gè)樣,用宏P(guān)HP_FUNCTION來包裝了一下,另外呢,在hello_functions里面添加了一行信息,表示你這個(gè)模塊中有這個(gè)函數(shù)了。
那么都是一樣的函數(shù)原型,如何區(qū)分返回值與參數(shù)呢? 我給一個(gè)例子:
- PHP_FUNCTION(hello_strdiff)
- {
- ????char?*r1?=?NULL,?*r2?=?NULL;
- ????int?n?=?0,?m?=?0;
- ????if?(zend_parse_parameters(ZEND_NUM_ARGS()?TSRMLS_CC,?"ss",?&r1,?&n,?&r2,?&m)?==?FAILURE)?{
- ????????return;
- ????}
- ????while(n?&&?m?&&?*r1?==?*r2)?{
- ????????r1++;
- ????????r2++;
- ????????n--;
- ????????m--;
- ????}
- ????if(n?==?0)?RETURN_LONG(m);
- ????if(m?==?0)?RETURN_LONG(n);
- ????int?d[n+1][m+1];
- ????int?cost;
- ????int?i,j;
- ????for(i?=?0;?i?<=?n;?i++)?d[i][0]?=?i;
- ????for(j?=?0;?j?<=?m;?j++)?d[0][j]?=?j;
- ????for(i?=?1;?i?<=?n;?i++)?{
- ????????for(j?=?1;?j?<=?m;?j++)?{
- ????????????if(r1[i-1]?==?r2[j-1])?cost?=?0;
- ????????????else?cost?=?1;
- ????????????int?a?=?MIN(d[i-1][j]+1,d[i][j-1]+1);
- ????????????a?=?MIN(a,?d[i-1][j-1]+cost);
- ????????????d[i][j]?=?a;
- ????????}
- ????}
- ????RETURN_LONG(d[n][m]);
- }
把這個(gè)當(dāng)成是scanf來理解好了。 類型說明見下表:
| Boolean | b | zend_bool |
| Long | l | long |
| Double | d | double |
| String | s | char*, int |
| Resource | r | zval* |
| Array | a | zval* |
| Object | o | zval* |
| zval | z | zval* |
那么返回值怎么辦呢? 使用下面一組宏來表示: RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL
注意RETURN_STRING有兩個(gè)參數(shù) 當(dāng)你需要復(fù)制一份字符串時(shí)使用 RETURN_STRING("Hello World", 1);
否則使用 RETURN_STRING(str, 0);
這里涉及到了模塊中內(nèi)存的分配,當(dāng)你申請(qǐng)的內(nèi)存需要php程序中去釋放的話,請(qǐng)參照如下表
| Traditional | Non-Persistent | Persistent |
|---|---|---|
malloc(count)calloc(count, num) | emalloc(count)ecalloc(count, num) | pemalloc(count, 1)*pecalloc(count, num, 1) |
strdup(str)strndup(str, len) | estrdup(str)estrndup(str, len) | pestrdup(str, 1)pemalloc() & memcpy() |
free(ptr) | efree(ptr) | pefree(ptr, 1) |
realloc(ptr, newsize) | erealloc(ptr, newsize) | perealloc(ptr, newsize, 1) |
malloc(count * num + extr)** | safe_emalloc(count, num, extr) | safe_pemalloc(count, num, extr) |
基本上就是這樣,可以開始寫一個(gè)php的擴(kuò)展了。 從我目前的應(yīng)用來看,能操縱字符串就夠用了,所以我就只能介紹這么多了,如果要詳細(xì)一點(diǎn)的呢,例如php數(shù)組怎么處理,可以參考 http://devzone.zend.com/node/view/id/1022
更詳細(xì)的呢,可以參考php手冊(cè)中的《Zend API:深入 PHP 內(nèi)核》一章 不過這些資料都是英文的。
?轉(zhuǎn)自:http://blog.csdn.net/oyd/article/details/3168417
?
另外可參考:http://www.phpchina.com/index.php?action-viewthread-tid-26870
http://blog.csdn.net/xiaocon/article/details/388953
總結(jié)
以上是生活随笔為你收集整理的php调用C代码的方法详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 描述硫酸铜提纯过程中发生的反应,写出可能
- 下一篇: ASP.NET的(HttpModule,