protobuf2
//required 不可以增加或删除的字段,必须初始化
//optional 可选字段,可删除,可以不初始化
//repeated 可重复字段,对应到C#文件里,生成的是List
protobuf3
syntax = "proto3";
//optional required 要去掉
//repeated 可重复字段,对应到C#文件里,生成的是List,类似于数组
1、syntax="proto3":表明使用的是proto3格式,如果不指定则为proto2
2、package test:定义包名为test,生成类时,会产生一个目录为test
3、message Person:消息主体内容,里面为各个字段的定义
4 protobuf2 和 protobuf3 生成的二进制是无法互相解析的. 也就是2的只能用2解析, 3的只能用3解析
required: 必须 格式正确的消息必须恰好具有此字段之一
optional: 可选 格式正确的邮件可以包含零个或一个此字段(但不能超过一个)
repeated: 多值 重复任意次(包括零次) repeated标量数字类型的字段编码效率不高。新代码应使用特殊选项[packed=true]来获得更有效的编码
单值字段(required/ optional)和多值字段(repeated)
reserved 保留字段
required/optional 实现的方法
get{FIELD}() // return field value
set{FIELD}($value) // set field value to $value
function serialize_field($field, $value)
{
$foo = new Foo();
$setter = 'set' . ucfirst($field) . 'Field';
$foo->{$setter}($value);
var_dump($foo->serializeToString());
}
repeated 实现的方法
append{FIELD}($value) // append $value value to field 向字段追加$value
clear{FIELD}() // empty field 空字段
get{FIELD}() // return array of field values 返回字段值的数组
getAt{FIELD}($index) // return field value at $index index 返回$index index处的字段值
getCount{FIELD}() // return number of field values 返回字段值的数目
getIterator{FIELD}($index) // return ArrayIterator for field values 返回字段值的ArrayIterator
PHP常用的使用方法:
序列化:
1、serializeToString:序列化成二进制字符串
2、serializeToJsonString:序列化成JSON字符串
反序列化:
1、mergeFromString:二进制字符串反序列化
2、mergeFromJsonString:Json字符串反序列化
。
.proto的message解析
1、定义:
类型 变量名=位置;
如:int32 age=1;
这里需要区分,变量名后面的数字意义为该变量内容在二进制序列中的位置而不是变量的值,该数字必须是唯一不可重复使用。
2、目前支持的类型:
double,float,int32,int64,uint32 ,uint64,sint32,sint64
,
fixed32,fixed64,sfixed32,sfixed64,bool,bytes
嵌套消息导致具有相同名称的PHP类以其包含的消息为前缀,并用下划线分隔,因为PHP不支持嵌套类
message TestMessage {
optional int32 a = 1;
message NestedMessage {...}
}
import
如果一个proto文件引用了另外一个proto文件,那么可以使用import关键字在头部申明:
import "User.proto";
PHP生成后
class TestMessage {
public a;
}
// PHP doesn’t support nested classes.
class TestMessage_NestedMessage {...}
3、message
message类似于结构体的概念,最终编译为代码在PHP、JAVA里就是一个类,在golang里是结构体。每一个属性都会生成对应的getXXX、setXXX方法。
message UserList {
repeated User list = 1; //用户列表
int32 page = 2; //分页
int32 limit = 3; //分页条数
}
php 写数据
设置 多条数据 类型的数据
$arr1 = [15,0,1,1]; $from->setFriends($arr1);// friends 多条数据类型
$from->getRequestid()[] = 3;//requestid 多条数据类型
$from->getRequestid()[] = 4;
$arr2 = [666,'qq','email']; $from->setRequestid($arr2);
4、字段规则
repeated表示这个属性重复N次,在相对应的编程语言中通常是一个空的list。PHP里对应数组。
reserved表示标识号保留暂时不用。
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
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)、packed 例: repeated int32 prop = 3 [packed=true];
如果repeated字段包含的val比较多,那么每个val都带上key是比较浪费的.
如果repeated字段设置了packed选项,则会使用Length-delimited格式来编码字段值。
8、引用类型
上面的UserList就引用了User类型。大家可以看一下
9、import
如果一个proto文件引用了另外一个proto文件,那么可以使用import关键字在头部申明:
import "User.proto";
10、Map类型
proto支持map属性类型的定义,语法如下:
map
示例:
map
这个map对于PHP来说就是关联数组,对于golang来说就是Map。
10、Any
Any类型允许包装任意的message类型,可以通过pack()和unpack()(方法名在不同的语言中可能不同)方法打包/解包:
import "google/protobuf/any.proto";
message Response {
google.protobuf.Any data = 1;
}
PHP开发的同学可能觉得Any没必要,因为数组里任何类型都可以放,但是对于强类型语言,数组里的值类型必须是一致的,使用Any类型可以解决这个问题。Any相当于把值包装了一层,这样都是Any类型。
11、服务定义
service UserService {
// 方法名 方法参数 返回值
rpc GetUser(Request) returns (Response);
}
这相当于定义了一个类,里面有一个对外的GetUser()方法。这个通常用于定义RPC服务,与gRPC结合使用。
12、从.proto文件生成了什么?
当用protocol buffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。
PHP:每一个Message或者Enum生成一个类,另外还会生成GPBMetadata。
C++:编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类。
Java:编译器为每一个消息类型生成了一个.java文件,以及一个特殊的Builder类(该类是用来创建消息类接口的)。
Python:Python编译器为.proto文件中的每个消息类型生成一个含有静态描述符的模块,该模块与一个元类(metaclass)在运行时(runtime)被用来创建所需的Python数据访问类。
go:编译器会位每个消息类型生成了一个.pd.go文件。
Ruby:编译器会为每个消息类型生成了一个.rb文件。
Objective-C:编译器会为每个消息类型生成了一个pbobjc.h文件和pbobjcm文件,.proto文件中的每一个消息有一个对应的类。
C#:编译器会为每个消息类型生成了一个.cs文件,.proto文件中的每一个消息有一个对应的类。
IDE插件
1、JetBrains PhpStorm 可以在插件里找到Protobuf安装,重启IDE后就支持proto格式语法了。
2、VScode 在扩展里搜索 Protobuf,安装即可。
3、protobuf的 php 扩展类在ide中没有提示,可将https://github.com/protocolbuffers/protobuf/tree/master/php/src 目录下载到本地,将此目录加到ide的include_path中即可。