C是靜態編譯的,執行效率比PHP代碼高不少。一樣的運算代碼,使用C來開發,性能會比PHP要提高數百倍。php
另外C擴展是在進程啓動時加載的,PHP代碼只能操做Request生命週期的數據,C擴展可操做的範圍更廣。數據庫
1.下載地址: http://php.net/get/php-7.1.1.tar.bz2/from/a/mirror vim
2.下載後進行解壓數組
##本例用的是php7.1.1 cd ext ./ext_skel --extname=helloworld
把下面幾行註釋打開,config.m4中 dnl 爲註釋的意思安全
##動態編譯選項,經過.so的方式連接,去掉dnl註釋: PHP_ARG_WITH(helloworld, for helloworld support, Make sure that the comment is aligned: [ --with-helloworld Include helloworld support]) ##靜態編譯選項,經過enable來啓用,去掉dnl註釋: PHP_ARG_ENABLE(helloworld, whether to enable helloworld support, Make sure that the comment is aligned: [ --enable-helloworld Enable helloworld support])
修改完成編譯下php7
phpize #這裏用本身的php-config文件位置 ./configure --with-php-config=./configure --with-php-config=/Applications/MAMP/bin/php/php7.1.1/bin/php-config make && make install make test #測試 #編輯php.ini,加上helloworld擴展 extension=helloworld.so
在myfun有個php的測試腳本,執行測試下函數
php -d enable_dl=On myfile.php
輸出結果:工具
Functions available in the test extension: confirm_myfun_compiled Congratulations! You have successfully modified ext/myfun/config.m4. Module myfun is now compiled into PHP.
其實confirm_myfun_compiled是構建工具幫咱們生成的測試函數性能
如今咱們來建立屬於本身的函數 helloWorld()
,功能就是輸出 Hello World!
測試
vim myfun/php_myfun.h
##在PHP_FUNCTION(confirm_myfun_compiled); 下追加一行
PHP_FUNCTION(helloWorld);
實現helloworld實體
vim myfun/myfun.c
##zend_function_entry myfun_functions 補充要實現的函數 const zend_function_entry myfun_functions[] = { PHP_FE(confirm_myfun_compiled, NULL) /* For testing, remove later. */ PHP_FE(helloWorld, NULL) /*這是補充的一行,末尾沒有逗號*/ {NULL, NULL, NULL} /* Must be the last line in myfun_functions[] */ }; ##在末尾實現helloworld的內容 PHP_FUNCTION(helloWorld) { php_printf("Hello World!\n"); RETURN_TRUE; }
從新編譯
./configure && make && make install
php -d enable_dl=On -r "dl('myfun.so');helloWorld();" Hello World! php -d enable_dl=On -r "dl('myfun.so');print confirm_myfun_compiled('helloWorld');" Congratulations! You have successfully modified ext/myfun/config.m4. Module helloWorld is now compiled into PHP.
#ifndef PHP_MYFUN_H #define PHP_MYFUN_H extern zend_module_entry myfun_module_entry; #define phpext_myfun_ptr &myfun_module_entry #ifdef PHP_WIN32 # define PHP_MYFUN_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_MYFUN_API __attribute__ ((visibility("default"))) #else # define PHP_MYFUN_API #endif #ifdef ZTS #include "TSRM.h" #endif PHP_MINIT_FUNCTION(myfun); /*當PHP被裝載時,模塊啓動函數即被引擎調用。這使得引擎作一些例如資源類型,註冊INI變量等的一次初始化。*/ PHP_MSHUTDOWN_FUNCTION(myfun); /*當PHP徹底關閉時,模塊關閉函數即被引擎調用。一般用於註銷INI條目*/ PHP_RINIT_FUNCTION(myfun); /*在每次PHP請求開始,請求前啓動函數被調用。一般用於管理請求前邏輯。*/ PHP_RSHUTDOWN_FUNCTION(myfun); /*在每次PHP請求結束後,請求前關閉函數被調用。常常應用在清理請求前啓動函數的邏輯。*/ PHP_MINFO_FUNCTION(myfun); /*調用phpinfo()時模塊信息函數被呼叫,從而打印出模塊信息。*/ PHP_FUNCTION(confirm_myfun_compiled); /* For testing, remove later. */ PHP_FUNCTION(helloWorld); #ifdef ZTS #define MYFUN_G(v) TSRMG(myfun_globals_id, zend_myfun_globals *, v) #else #define MYFUN_G(v) (myfun_globals.v) #endif #endif /* PHP_MYFUN_H */
PHP_FUNCTION(confirm_myfun_compiled) //使用了宏PHP_FUNCTION(),該宏能夠生成一個適合於Zend引擎的函數原型 { char *arg = NULL; int arg_len, len; char *strg; //得到函數傳遞的參數 //第一個參數是傳遞給函數的參數個數。一般的作法是傳給它ZEND_NUM_ARGS()。這是一個表示傳遞給函數參數總個數的宏。 //第二個參數是爲了線程安全,老是傳遞TSRMLS_CC宏。 //第三個參數是一個字符串,指定了函數指望的參數類型,後面緊跟着須要隨參數值更新的變量列表。由於PHP採用鬆散的變量定義和動態的類型判斷,這樣作就使得把不一樣類型的參數轉化爲指望的類型成爲可能。例如,若是用戶傳遞一個整數變量,可函數須要一個浮點數,那麼zend_parse_parameters()就會自動地把整數轉換爲相應的浮點數。若是實際值沒法轉換成指望類型(好比整形到數組形),會觸發一個警告。 /* 類型指示符 l long 符號整數 d double 浮點數 s char *, int 二進制字符串,長度 b zend_bool 邏輯型(1或0) r zval * 資源(文件指針,數據庫鏈接等) a zval * 聯合數組 o zval * 任何類型的對象 O zval * 指定類型的對象。須要提供目標對象的類類型 z zval * 無任何操做的zval */ //第四個參數爲傳遞的參數數據的引用 //第五個參數爲傳遞的參數個數 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.", "myfun", arg); /* 經過設置RETURN_type()的方式,將返回控制到PHP。下表解釋了大多數存在的宏。 RETVAL_LONG(l) 整數 RETVAL_BOOL(b) 布爾數(1或0) RETVAL_NULL() NULL RETVAL_DOUBLE(d) 浮點數 RETVAL_STRING(s, dup) 字符串。若是dup爲1,引擎會調用estrdup()重複s,使用拷貝。若是dup爲0,就使用s RETVAL_STRINGL(s, l, dup) 長度爲l的字符串值。與上一個宏同樣,但由於s的長度被指定,因此速度更快。 RETVAL_TRUE 返回布爾值true。注意到這個宏沒有括號。 RETVAL_FALSE 返回布爾值false。注意到這個宏沒有括號。 RETVAL_RESOURCE(r) 資源句柄。 */ RETURN_STRINGL(strg, len, 0); }