Protobuf 小试牛刀 (2)

接下来,我们写个例子看看如何使用生成的Model。在使用之前需要处理下GPBMetadata相关的命名空间问题,这里我们定义的命名空间是Sample\Model,但是 GPBMetadata/User.php以及Sample/Model/User.php的命名空间我们希望调整下,都以Sample\Model开头,而不是GPBMetadata。下面我们使用命令行处理:

cd protobuf-sample #修改GPBMetadata命名空间 cd php mv -f GPBMetadata Sample/Model/ find . -name '*.php' ! -name example.php -exec sed -i -e 's#GPBMetadata#Sample\\Model\\GPBMetadata#g' -e 's#\\Sample\\Model\\GPBMetadata\\Google#\\GPBMetadata\\Google#g' {} \; cd -

接下来我们写个测试文件:
user.php

<?php use Sample\Model\User; use Sample\Model\UserList; ini_set("display_errors", true); error_reporting(E_ALL); require_once "autoload.php"; $user = new User(); $user->setId(1)->setName("test"); $userList = new UserList(); $userList->setPage(1)->setLimit(5)->setList([$user]); print_r($userList); var_dump($userList->getPage()); print_r($userList->getList()); foreach ($userList->getList() as $key => $obj) { print_r($obj); echo $obj->getId() .PHP_EOL; }

autoload.php是实现自动加载的。

我们运行:

$ php tests/user.php Sample\Model\UserList Object /work/git/protobuf-sample/tests/user.php:15: int(1) Google\Protobuf\Internal\RepeatedField Object ( ) Sample\Model\User Object 1 {"list":[{"id":1,"name":"test"}],"page":1,"limit":5}

可以看到使用var_dump、print_r等函数是打印不出来 protobuf生成的对象的,但是里面确实是有内容的,只有标量能打印出来,或者序列化为字符串。

我们也可以将一个字符串反序列化为protobuf对象:
user_merge.php

<?php use Sample\Model\UserList; $json = '{"list":[{"id":1,"name":"test"}],"page":1,"limit":5}'; require_once "autoload.php"; $userList = new UserList(); $userList->mergeFromJsonString($json); print_r($userList); echo $userList->serializeToJsonString();

运行示例:

$ php tests/user_merge.php Sample\Model\UserList Object {"list":[{"id":1,"name":"test"}],"page":1,"limit":5} proto语法

这里只将介绍简单的,如果需要细研究,请查看官方文档。

官方文档:https://developers.google.com/protocol-buffers/docs/overview

1、proto3
proto 有proto3 和 proto2。proto3 比 proto2 支持更多语言但 更简洁。去掉了一些复杂的语法和特性,更强调约定而弱化语法。如果是首次使用 Protobuf ,建议使用 proto3 。详见参考文献说明。

需要在proto头部申明:

syntax = "proto3";

如果你没有指定这个,编译器会使用proto2。

2、注释
使用 //,示例:

message UserList { repeated User list = 1; //用户列表 int32 page = 2; //分页 int32 limit = 3; //分页条数 }

其中写在每个属性后面的注释在生产的代码里面有保留。

3、message
message类似于结构体的概念,最终编译为代码在PHP、JAVA里就是一个类,在golang里是结构体。每一个属性都会生成对应的getXXX、setXXX方法。

4、字段规则
repeated表示这个属性重复N次,在相对应的编程语言中通常是一个空的list。PHP里对应数组。

reserved表示标识号保留暂时不用。

message Foo { reserved 2, 15, 9 to 11; reserved "foo", "bar"; }

在消息定义中,每个字段都有唯一的一个数字标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。

5、支持的数据类型

Protobuf 小试牛刀

详情参看官方文档:

6、默认值说明

string类型,默认值是空字符串

bytes类型,默认值是空bytes

bool类型,默认值是false

数字类型,默认值是0

枚举类型,默认值是第一个枚举值,即0

repeated修饰的属性,默认值是空.

7、枚举
使用enum关键字定义枚举,值必须从0开始:

enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; }

8、引用类型
上面的UserList就引用了User类型。大家可以看一下。

9、import
如果一个proto文件引用了另外一个proto文件,那么可以使用import关键字在头部申明:

import "User.proto";

10、Map类型
proto支持map属性类型的定义,语法如下:

map<key_type,value_type> map_field = N;

示例:

map<string, string> ext = 6; //扩展信息

这个map对于PHP来说就是关联数组,对于golang来说就是Map。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwzdgx.html