使用golang開發PHP擴充套件
環境
- golang 1.18 (低版本沒嘗試,應該也可以)
- Linux
- PHP7.4 原始碼安裝 (PHP8.x PHP5.X 沒有嘗試)
程式碼組成
config.m4
function.go
main.go
config.m4檔案:PHP腳手架ext_skel生成
main.go
package main
//#cgo CFLAGS: -g -I /home/php7/install/include/php -I /home/php7/install/include/php/main -I /home/php7/install/include/php/TSRM -I /home/php7/install/include/php/Zend -I /home/php7/install/include/php/ext -I /home/php7/install/include/php/ext/date/lib -DHAVE_CONFIG_H
//#cgo LDFLAGS: -Wl,--export-dynamic -Wl,--unresolved-symbols=ignore-all
/*
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
static int le_go2php;
PHP_MINIT_FUNCTION(go2php)
{
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(go2php)
{
return SUCCESS;
}
PHP_RINIT_FUNCTION(go2php)
{
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(go2php)
{
return SUCCESS;
}
PHP_MINFO_FUNCTION(go2php)
{
php_info_print_table_start();
php_info_print_table_header(2, "go2php support", "enabled");
php_info_print_table_end();
}
PHP_FUNCTION(go2php_print)
{
zend_long a,b;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_LONG(a)
ZEND_PARSE_PARAMETERS_END();
b = calcFib(a);
RETURN_LONG(b);
}
ZEND_BEGIN_ARG_INFO(null, 0)
ZEND_END_ARG_INFO()
const zend_function_entry go2php_functions[] = {
ZEND_FE(go2php_print, null)
PHP_FE_END
};
zend_module_entry go2php_module_entry = {
STANDARD_MODULE_HEADER,
"go2php",
go2php_functions,
PHP_MINIT(go2php),
PHP_MSHUTDOWN(go2php),
PHP_RINIT(go2php),
PHP_RSHUTDOWN(go2php),
PHP_MINFO(go2php),
"0.1.0",
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_GO2PHP
ZEND_GET_MODULE(go2php)
#endif
*/
import "C"
func main() {}
CFLAGS -g -I
g引數是支援gdb除錯資訊
I引數是指定匯入標頭檔案路徑 (根據你PHP環境安裝的位置,請替換{/home/php7/install/include/php}中的{/home/php7/install}路徑。防止編譯的時候C找不到標頭檔案)
function.go
這個是用golang語法寫的C語言介面的函式,通過export關鍵字,匯出為C的函式,注意引數和返回值要是C語言友好的型別,比如C.int *C.char等,相關內容可以去系統的學習下CGO的語法。
package main
import "C"
//export calcFib
func calcFib(i int) int {
if i < 2 {
return i
}
return calcFib(i-1) + calcFib(i-2)
}
使用golang寫內部功能和業務邏輯比用Zend巨集命令和C來寫PHP擴充套件來的簡單一些,不需要去理解zend的過多巨集命令,只需要瞭解PHP的擴充套件宣告,方法宣告,引數獲取和型別轉換。雖然CGO效能相比較純golang和php的原生擴充套件,效能會有一些下降,但是開發效率和執行效率並不是很差,夠用。
以上程式碼和環境準備好之後,進入編譯連結階段
- cd 到當前的原始碼目錄
- 執行 {你的php安裝目錄}/bin/phpize (phpize是PHP環境的bin目錄下的phpize工具)
- 執行完phpize命令之後,你會看到下面多出了很多檔案
ls autom4te.cache build config.h.in config.m4 configure configure.ac function.go go.mod main.go run-tests.php test.php
- 執行 ./configure –with-php-config={你的php安裝目錄}/bin/php-config PHP擴充套件安裝的常規操作步驟之一
- 執行完./configure命令之後,你會看到下面又多出了很多檔案,其中config.h是之前main.go 原始碼裡需要的一個標頭檔案,就在這一步生成的。
ls autom4te.cache config.h config.log config.nice configure function.go include main.go Makefile.fragments modules test.php build config.h.in config.m4 config.status configure.ac go.mod libtool Makefile Makefile.objects run-tests.php
- 最終階段生成動態連結庫SO
go build -gcflags “-l” -buildmode=c-shared -o go2php.so *.go
上面操作沒有錯誤的話,將會生成so檔案,這個就是PHP擴充套件檔案了,然後將so擴充套件copy到php的擴充套件安裝位置,然後去php.ini 增加extension=go2php
然後php -m 檢視是否成功安裝擴充套件。 - 測試
寫一個php指令碼
執行上面指令碼看是否正常輸出你期待的結果。<?php echo go2php_print(10);
原始碼地址
github.com/529124368/golangToPHP
本作品採用《CC 協議》,轉載必須註明作者和本文連結