1. 程式人生 > >一次失敗的PHP擴充套件開發之旅

一次失敗的PHP擴充套件開發之旅

2. 進入php原始碼包的ext目錄,藉助ext_skel工具生成外掛架子程式碼

cd ext
./ext_skel --extname=demo

3. 編輯config.m4,開啟PHP_ARG_WITH或者PHP_ARG_ENABLE選項(說實話區別仍沒搞清楚,求達人指點),新增C++支援、依賴路徑等

PHP_ARG_ENABLE(demo, whether to enable demo support,
    [  --enable-demo           Enable demo support])

if test "$PHP_DEMO" != "no"; then
  PHP_REQUIRE_CXX()
  PHP_ADD_LIBRARY(stdc++, 1, EXTRA_LDFLAGS)

  PHP_ADD_INCLUDE(/root/spp/module/include/)
  PHP_ADD_INCLUDE(/root/spp/module/include/spp_incl/)

  PHP_NEW_EXTENSION(demo, demo.cpp, $ext_shared)
fi

4. 編輯demo.cpp,新增擴充套件定義和實現(函式、類、變數 ...),這裡僅僅給出函式定義示例,類相關的有興趣的讀者自行根據附錄摸索。這裡給出的sendrecv函式定義比較有代表性,其中第3個引數rsp為引用引數,負責將接收到的資料返回給PHP呼叫方

ZEND_BEGIN_ARG_INFO_EX(arginfo_sendrecv, 0, 0, 7)
    ZEND_ARG_INFO(0, req)
    ZEND_ARG_INFO(0, req_len)
    ZEND_ARG_INFO(1, rsp)
    ZEND_ARG_INFO(0, rsp_len)
    ZEND_ARG_INFO(0, ip)
    ZEND_ARG_INFO(0, port)
    ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
PHP_FUNCTION(sendrecv)
{
    char *req = NULL;
    int req_str_len = 0;
    long req_len = 0;
    zval *rsp = NULL;
    long rsp_len = 0;
    char *ip = NULL;
    int ip_str_len = 0;
    long port = 0;
    long timeout = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slzlsll", &req, &req_str_len,
&req_len, &rsp, &rsp_len, &ip, &ip_str_len, &port, &timeout) == FAILURE) {
        return;
}   
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(std::string(ip, ip_str_len).c_str());
    addr.sin_port = htons(port);
    char *rsp_buf = (char *)emalloc(rsp_len);
    int rsp_buf_len = rsp_len;
    if (int ret = mt_udpsendrcv(&addr, req, req_len > req_str_len ? req_str_len : req_len, rsp_buf, rsp_buf_len, timeout)) {
        efree(rsp_buf);
        RETURN_LONG(ret);
    }
    zval_dtor(rsp);
    ZVAL_STRINGL(rsp, rsp_buf, rsp_buf_len, 0);
    RETURN_LONG(0);
}
const zend_function_entry demo_functions[] = {
    PHP_FE(sendrecv, arginfo_sendrecv)
    PHP_FE_END  /* Must be the last line in demo_functions[] */
};

5. 一切準備就緒,可以編譯擴充套件了,我個人比較喜歡動態編譯(靜態編譯需要重新編譯php原始碼,太耗時費力),生成的.so位於當前擴充套件的modules目錄下

/usr/local/bin/phpize
./configure --with-php-config=/usr/local/bin/php-config
make

6. 編輯php.ini檔案,新增新的擴充套件,然後就可以愉快地在PHP程式碼中呼叫新擴充套件了

extension_dir="/somewhere/modules"
extension="demo.so"
extension="xxxx.so"

高潮