您的位置:首页 > 编程语言 > C语言/C++

PHP扩展封装Protobuf反序列化方法(c++)

2009-09-01 10:08 876 查看
据说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了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: