php调用C代码的方法详解
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                php调用C代码的方法详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                在php程序中需要用到C代碼,應該是下面兩種情況:
1 已有C代碼,在php程序中想直接用 2 由于php的性能問題,需要用C來實現部分功能針對第一種情況,最合適的方法是用system調用,把現有C代碼寫成一個獨立的程序。參數通過命令行或者標準輸入傳入,結果從標準輸出讀出。其次,稍麻煩一點的方法是C代碼寫成一個daemon,php程序用socket來和它進行通訊。
重點講講第二種情況,雖然沿用system調用的方法也可以,但是想想你的目的是優化性能,那么頻繁的起這么多進程,當然會讓性能下降。而寫daemon的方法固然可行,可是繁瑣了很多。
我的簡單測試,同樣一個算法,用C來寫比用php效率能提高500倍。而用php擴展的方式,也能提高90多倍(其中的性能損失在了參數傳遞上了吧,我猜)。
所以有些時候php擴展就是我們的最佳選擇了。
這里我著重介紹一下用C寫php擴展的方法,而且不需要重新編譯php。
首先,找到一個php的源碼,php4或者php5版本的都可以,與你目標平臺的php版本沒有關系。
在源碼的ext目錄下可以找到名為ext_skel的腳本 在這個目錄下執行 #./ext_skel?--extname=hello 這時生成了一個目錄 hello,目錄下有幾個文件,你只需要關心這三個:config.m4?hello.c php_hello.h
把這個目錄拷備到任何你希望的地方,cd進去,依次執行 #phpize #./configure #make 什么也沒發生,對吧? 這是因為漏了一步,打開config.m4,找到下面 dnl If your extension references something external, use with:
... dnl Otherwise use enable:
... 這是讓你選擇你的擴展使用with還是enable,我們用with吧。把with那一部分取消注釋。 如果你和我一樣使用vim編輯器,你就會很容易發現dnl三個字母原來是表示注釋的呀(這是因為vim默認帶了各種文件格式的語法著色包)
我們修改了config.m4后,繼續 #phpize #./configure #make 這時,modules下面會生成hello.so和hello.la文件。一個是動態庫,一個是靜態庫。
你的php擴展已經做好了,盡管它還沒有實現你要的功能,我先說說怎么使用這個擴展吧!ext_skel為你生成了一個hello.php里面有調用示例,但是那個例子需要你把hello.so拷貝到php的擴展目錄中去,我們只想實現自己的功能,不想打造山寨版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()
 
隨后一個讓人關心的問題是,如何添加函數、實現參數傳遞和返回值
添加函數步驟如下: php_hello.h: PHP_FUNCTION(confirm_hello_compiled);// 括號里面填寫函數名
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)? {// 這里寫函數體 } 要實現的函數原型其實都一個樣,用宏PHP_FUNCTION來包裝了一下,另外呢,在hello_functions里面添加了一行信息,表示你這個模塊中有這個函數了。
那么都是一樣的函數原型,如何區分返回值與參數呢? 我給一個例子:
- 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]);
 - }
 
把這個當成是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有兩個參數 當你需要復制一份字符串時使用 RETURN_STRING("Hello World", 1);
否則使用 RETURN_STRING(str, 0);
這里涉及到了模塊中內存的分配,當你申請的內存需要php程序中去釋放的話,請參照如下表
| 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) | 
基本上就是這樣,可以開始寫一個php的擴展了。 從我目前的應用來看,能操縱字符串就夠用了,所以我就只能介紹這么多了,如果要詳細一點的呢,例如php數組怎么處理,可以參考 http://devzone.zend.com/node/view/id/1022
更詳細的呢,可以參考php手冊中的《Zend API:深入 PHP 內核》一章 不過這些資料都是英文的。
?轉自: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
總結
以上是生活随笔為你收集整理的php调用C代码的方法详解的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 描述硫酸铜提纯过程中发生的反应,写出可能
 - 下一篇: ASP.NET的(HttpModule,