一般而言,php速度已經比較快,但是,對於一些較進階開發人員而言,如果想要追求更快的速度,那毫無疑問可以通過自己寫c代碼,並編譯為動態連結程式庫(常為.so檔案),然後php通過建立一個新的擴充(extension),並在擴充裡調用該.so檔案,同時對外暴露出php函數介面。
在實際使用中,只要調用該函數介面,即可使用底層更快速的c函數服務。
一、動態連結程式庫(shared)
動態連結程式庫的檔案名稱尾碼通常是 ".so"。在Windows系統中,其檔案名稱尾碼是".dll"。
程式如果是和動態串連庫進行連結(link),程式運行時需要能夠找到相應的動態連結程式庫檔案。
使用動態連結程式庫存編譯的程式在運行時要求使用者的機器上必需也安裝了相應的動態連結程式庫檔案,這些庫檔案需要放置在特定的目錄,以讓程式能夠載入這些庫。
雖然這似乎沒有使用靜態連結庫的程式使用方便,但卻減少了程式的大小。對於那些會被很多程式使用到的庫,使用動態連結的好處就更加明顯了。
動態連結程式庫的製作:
gcc -shared -fPIC -o libmylib.so mylib.c ; # 編譯成為shared library
選項-fPIC在AMD64上是必須的,其它平台是則不是必要選項。
包含靜態連結庫到動態連結程式庫中
編譯動態連結程式庫時,如果需要連結靜態庫,並把連結庫的內容包含到要編譯的動態庫中,可以使用選項-Wl,--whole-archive。
例如:
gcc -shared -o libmylib.so -Wl,--whole-archive libmylib.a \ -Wl,--no-whole-archive libother.a
上面的-Wl表示傳遞給linker(連結器)。
二、調用動態C/C++連結庫
下面,本文的開發環境背景是CentOS release 6.5 。為了能夠調用c庫,我們的php 5.6.9,apache 2.4均是下載源碼並編譯的,不可直接通過yum安裝!請注意。至於php和apache的源碼編譯本文不提,只要注意在configure開啟合適開關即可。
具體步驟如下:
將共用庫.so添加入系統配置中(假設共用庫名為 'libhello.so')
cp libhello.so /usr/local/lib echo /usr/local/lib > /etc/ld.so.conf.d/local.conf /sbin/ldconfig
在php/ext目錄下建立擴充標頭檔,取名為myfunctions.def
在該檔案裡填寫c函式宣告即可。每個函數一行。
string hello(int a) int hello_add(int a, int b)
使用ext_skel搭建擴充骨架
./ext_skel --extname=myfunctions --proto=myfunctions.def
開啟config.m4 中的enable開關
PHP_ARG_ENABLE(myfunctions, whether to enable myfunctions support, [ --enable-myfunctions Include myfunctions support])
上面把擴充骨架建立好了,下面重新設定php (下面是我個人設定檔,讀者需要結合自己情況修改)
./buildconf --force //產生新配置指令碼 './configure' '--prefix=/usr/local/php' '--with-libdir=lib64' '--enable-fpm' '--with-fpm-user=php-fpm' '--with-fpm-group=www--enable-mysqlnd' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--enable-opcache' '--enable-pcntl' '--enable-mbstring' '--enable-soap' '--enable-zip' '--enable-calendar' '--enable-bcmath' '--enable-exif' '--enable-ftp' '--enable-intl' '--with-openssl' '--with-zlib' '--with-curl' '--with-gd' '--with-zlib-dir=/usr/lib' '--with-png-dir=/usr/lib' '--with-jpeg-dir=/usr/lib' '--with-gettext' '--with-mhash' '--with-ldap' '--disable-fileinfo' '--with-config-file-path=/usr/local/php/etc' '--with-apxs2=/usr/local/httpd/bin/apxs' '--enable-myfunctions' // 配置
記住!一定在末尾加上 —enable-myfunctions 。這樣子才會被編譯進php中。
當擴充編譯進去了之後,就可以開始修改擴充裡的myfunctions.c檔案,在裡面可以添加php->c的轉接函數,在轉接函數裡可以調用.so內的函數。
比如要添加一個hello_add的php函數,裡面可以調用c函數add(int a, int b)
a. 添加函式宣告
b. 添加php函數
PHP_FUNCTION(hello_add){ ... }
注意,在該函數裡,如果調用了.so檔案裡的介面函數,那麼待會在make的時候,要指定所使用的.so共用庫,該共用庫必須完成第1步中添加到系統配置的操作。
如果調用了.so檔案,那麼要在php/Makefile中添加
Extra_LDFLAG = -lhello //對應前面的libhello.soExtra_libs = -lhello(make clean)
每次修改完上面的c檔案,都要重新make
重啟apache伺服器
在phpinfo裡可以看到新擴充,可以直接在php調用新擴充內的函數。