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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

php调用C代码的方法详解

發(fā)布時(shí)間:2023/11/27 生活经验 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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,改用我下面的方法來加載吧:
  1. if(!extension_loaded("hello"))?{
  2. ????????dl_local("hello.so");
  3. }
  4. function?dl_local(?$extensionFile?)?{
  5. ????????//make?sure?that?we?are?ABLE?to?load?libraries
  6. ????????if(?!(bool)ini_get(?"enable_dl"?)?||?(bool)ini_get(?"safe_mode"?)?)?{
  7. ????????????????die(?"dh_local():?Loading?extensions?is?not?permitted./n"?);
  8. ????????}
  9. ????????//check?to?make?sure?the?file?exists
  10. ????????if(?!file_exists(dirname(__FILE__)?.?"/".?$extensionFile?)?)?{
  11. ????????????????die(?"dl_local():?File?'$extensionFile'?does?not?exist./n"?);
  12. ????????}
  13. ????????//check?the?file?permissions
  14. ????????if(?!is_executable(dirname(__FILE__)?.?"/".?$extensionFile?)?)?{
  15. ????????????????die(?"dl_local():?File?'$extensionFile'?is?not?executable./n"?);
  16. ????????}
  17. ????????//we?figure?out?the?path
  18. ????????$currentDir?=?dirname(__FILE__)?.?"/";
  19. ????????$currentExtPath?=?ini_get(?"extension_dir"?);
  20. ????????$subDirs?=?preg_match_all(?""?,?$currentExtPath?,?$matches?);
  21. ????????unset(?$matches?);
  22. ????????//lets?make?sure?we?extracted?a?valid?extension?path
  23. ????????if(?!(bool)$subDirs?)?{
  24. ????????????????die(?"dl_local():?Could?not?determine?a?valid?extension?path?[extension_dir]./n"?);
  25. ????????}
  26. ????????$extPathLastChar?=?strlen(?$currentExtPath?)?-?1;
  27. ????????if(?$extPathLastChar?==?strrpos(?$currentExtPath?,?"/"?)?)?{
  28. ????????????????$subDirs--;
  29. ????????}
  30. ????????$backDirStr?=?"";?
  31. ????????for(?$i?=?1;?$i?<=?$subDirs;?$i++?)?{
  32. ????????????????$backDirStr?.=?"..";
  33. ????????????????if(?$i?!=?$subDirs?)?{
  34. ??????????????????$backDirStr?.=?"/";
  35. ????????????????}
  36. ????????}
  37. ????????//construct?the?final?path?to?load
  38. ????????$finalExtPath?=?$backDirStr?.?$currentDir?.?$extensionFile;
  39. ????????//now?we?execute?dl()?to?actually?load?the?module
  40. ????????if(?!dl(?$finalExtPath?)?)?{
  41. ????????????????die();
  42. ????????}
  43. ????????//if?the?module?was?loaded?correctly,?we?must?bow?grab?the?module?name
  44. ????????$loadedExtensions?=?get_loaded_extensions();
  45. ????????$thisExtName?=?$loadedExtensions[?sizeof(?$loadedExtensions?)?-?1?];
  46. ????????//lastly,?we?return?the?extension?name
  47. ????????return?$thisExtName;
  48. }//end?dl_local()
這樣的好處是你的php擴(kuò)展可以隨你的php代碼走,綠色擴(kuò)展。
隨后一個(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è)例子:
  1. PHP_FUNCTION(hello_strdiff)
  2. {
  3. ????char?*r1?=?NULL,?*r2?=?NULL;
  4. ????int?n?=?0,?m?=?0;
  5. ????if?(zend_parse_parameters(ZEND_NUM_ARGS()?TSRMLS_CC,?"ss",?&r1,?&n,?&r2,?&m)?==?FAILURE)?{
  6. ????????return;
  7. ????}
  8. ????while(n?&&?m?&&?*r1?==?*r2)?{
  9. ????????r1++;
  10. ????????r2++;
  11. ????????n--;
  12. ????????m--;
  13. ????}
  14. ????if(n?==?0)?RETURN_LONG(m);
  15. ????if(m?==?0)?RETURN_LONG(n);
  16. ????int?d[n+1][m+1];
  17. ????int?cost;
  18. ????int?i,j;
  19. ????for(i?=?0;?i?<=?n;?i++)?d[i][0]?=?i;
  20. ????for(j?=?0;?j?<=?m;?j++)?d[0][j]?=?j;
  21. ????for(i?=?1;?i?<=?n;?i++)?{
  22. ????????for(j?=?1;?j?<=?m;?j++)?{
  23. ????????????if(r1[i-1]?==?r2[j-1])?cost?=?0;
  24. ????????????else?cost?=?1;
  25. ????????????int?a?=?MIN(d[i-1][j]+1,d[i][j-1]+1);
  26. ????????????a?=?MIN(a,?d[i-1][j-1]+cost);
  27. ????????????d[i][j]?=?a;
  28. ????????}
  29. ????}
  30. ????RETURN_LONG(d[n][m]);
  31. }
這是一個(gè)求兩個(gè)字符串差異度的算法,輸入?yún)?shù)兩個(gè)字符串,返回整型。 參數(shù)的傳遞看這里 zend_parse_parameters(ZEND_NUM_ARGS()?TSRMLS_CC,?"ss",?&r1,?&n,?&r2,?&m)
把這個(gè)當(dāng)成是scanf來理解好了。 類型說明見下表:
Booleanbzend_bool
Longllong
Doubleddouble
Stringschar*, int
Resourcerzval*
Arrayazval*
Objectozval*
zvalzzval*
如果想實(shí)現(xiàn)可選參數(shù)的話,例如一個(gè)字符串,一個(gè)浮點(diǎn),再加一個(gè)可選的bool型,可以用"sd|b"來表示。 和scanf有一點(diǎn)不同的是,對(duì)于字符串,你要提供兩個(gè)變量來存儲(chǔ),一個(gè)是char *,存字符串的地址,一個(gè)int,來存字符串的長(zhǎng)度。這樣有必要的時(shí)候,你可以安全的處理二進(jìn)制數(shù)據(jù)。
那么返回值怎么辦呢? 使用下面一組宏來表示: 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)參照如下表
TraditionalNon-PersistentPersistent
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)
一般我們使用Non-Persistent中列出的這些好了。
基本上就是這樣,可以開始寫一個(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)容,希望文章能夠幫你解決所遇到的問題。

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