PHP擴充封裝Protobuf還原序列化方法(c++)

來源:互聯網
上載者:User

據說google的protobuf效率很高,我們決定嘗試一下,使用到php項目中,作為還原序列化的協議,調用.net的soa介面。

 

由於protobuf的源碼只有java、c++、Python,我選用了c++作為開發語言,進行PHP擴充的開發。

 

首先,注意到與用c做PHP擴充的幾點不同,主要集中在config.m4中:

 

 

PHP_ARG_ENABLE(protophp, whether to enable protophp support,

[  --enable-protophp           Enable protophp support])

 

if test "$PHP_PROTOPHP" != "no"; then

 

 

  PHP_REQUIRE_CXX()

  PHP_ADD_LIBRARY(stdc++, "", EXTRA_LDFLAGS)

  PHP_ADD_LIBRARY(protobuf, "", EXTRA_LDFLAGS)

 

  AC_DEFINE(HAVE_PROTOPHPLIB,1,[ ])

  CPPFILE="protophp.cpp addressbook.pb.cpp"

  PHP_NEW_EXTENSION(protophp, $CPPFILE, $ext_shared)

fi

 

 

其中PHP_REQUIRE_CXX()指明了使用c++作為開發語言,所以也就是用g++作為編譯器。

PHP_ADD_LIBRARY將c++標準庫和protobuf的庫包含進來。

同時,由於根據protobuf協議,針對每個data類,都需要有一個.h和.cpp檔案,所以CPPFILE不但要包含我們的PHP擴充源碼,也要包含對應的data類代碼。

 

另外,我們將.c檔案重新命名為.cpp檔案。這裡,可以看到我們的PHP擴充模組名為:PROTOPHP。

 

然後,在protophp.cpp中,調用protobuf的parse方法:

 

    tutorial::AddressBook address_book;

    address_book.ParseFromString(str);

 

 

這時,address_book對象已經產生,但是要使其能被php代碼使用,還要針對每個類,寫一個object to array的方法。

 

或許還有別的方法?

 

那麼,這時我們看到,如果使用這種方法,每當添加 一個新的data類,我們需要修改以下4處:

1、添加class.h檔案

2、添加class.cpp 檔案

3、在config.m4的CPPFILE中添加class.cpp

4、在protophp.cpp開頭include <class.h>

 

應該還有別的更簡便的方法,我繼續學習。

 

------------------------------------------------------------

繼續更改,希望能夠通過字串類名動態產生c++的類,但是由於C++不支援這樣的動態編譯,所以需要折中修改。

 

首先,在PHP擴充中維持一個全域數組:

 

 

#include "addressbook.pb.h"

// 類名與相應初始函數的映射

typedef void (*cyFactoryParser_Ptr)(string protostr, zval** return_value);

 

typedef struct { 

    char * class_name;              // 類名

    cyFactoryParser_Ptr parser; // 對象初始化+轉化為數組

} TclassNameToFunc;

 

static TclassNameToFunc classInfo[] = { // 如果有新增類,修改這裡

    {"AddressBook", tutorial::AddressBook::cyparser}

};

 

其中由某個類的字串類名,映射到具體的處理函數。該處理函數需要在每次添加新的data類的時候,添加到該全域數組中。也就是說,除了通過protoc工具根據proto檔案產生c++的.h和.cc檔案之外,還要在.h或者.cc檔案中添加自己的parser函數。

 

從而,在PHP擴充的函數主題部分,其實就很簡單了:

 

// 尋找合適的處理函數

    for(classInfoIdx=0; classInfoIdx < classInfoLen; ++classInfoIdx){

        cla_func = classInfo[classInfoIdx];

        if (!strcmp(cla_func.class_name, class_name)){

            break;

        }

    }

 

 // 沒找到

    if (classInfoIdx == classInfoLen){

        cerr << "can't find!" << endl;

        RETURN_FALSE;

    }

 

 // 初始化傳回值:數組

    array_init(return_value);

 

    // 處理

    cla_func.parser(str, &return_value);

 

這裡,為了能夠直接將C++的對象,變成傳回值返回給php代碼,所以需要在parser函數的定義處 include "php.h"檔案。

 

但是這裡,就出現了一個error: 

 

/usr/local/include/google/protobuf/descriptor.pb.h:1165:64: error: macro "add_method" requires 3 arguments, but only 1 given

/usr/local/include/google/protobuf/descriptor.pb.h:3316:86: error: macro "add_method" requires 3 arguments, but only 1 given

 

經過排查protobuf和php的源碼,發現Zend裡有一個宏也叫add_method,所以衝突了。修改protobuf的函數名稱為cyadd_method,然後重新編譯protobuf,重新make,就ok了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.