php 使用 protobuf

发布于 2022-04-19 14:55 阅读 1264

协议缓冲区(Protocol Buffers)是一种语言中立、平台中立的可扩展机制,用于序列化结构化数据。

安装

wget https://github.com/protocolbuffers/protobuf/releases/download/v3.20.0/protobuf-php-3.20.0.tar.gz
tar -zxvf protobuf-php-3.20.0.tar.gz
cd protobuf-3.20.0
./configure --prefix=/usr/local/protobuf
make
make install

#软链
ln -s /usr/local/protobuf/bin/protoc /usr/bin/

php extension and library

extension 和 library 二选一

extension

cd ext/google/protobuf
pear package
sudo pecl install protobuf-{VERSION}.tgz

library

composer require google/protobuf

测试

vi person.proto
syntax="proto3";
package test;
message Person{
    string name=1;//姓名
    int32  age=2;//年龄
    bool sex=3;//性别
}

#生成php代码
protoc --php_out=./ person.proto

#即
GPBMetadata/Person.php
Test/Person.php

# 使用
<?php
require_once __DIR__ . '/../vendor/autoload.php';
include 'GPBMetadata/Person.php';
include 'Test/Person.php';

//序列化
//$person = new Test\Person();
//$person->setName("lailaiji");
//$person->setAge("28");
//$person->setSex(true);
//$data = $person->serializeToString();
//file_put_contents('data.bin', $data);

//反序列化
$bindata = file_get_contents('./data.bin');
$person = new Test\Person();
$person->mergeFromString($bindata);
echo $person->getName();

逆向推理

假如我们拿到一个序列化后的数据,比如:data.bin,怎么解析呢?

首先,使用命令decode一下

root@php-fpm:/var/www/php-demo/protobuf# protoc --decode_raw < data.bin 
1: "\345\274\240\344\270\211"
2: 28
3: 1
4 {
  1: "\345\214\227\344\272\254"
  2: "\346\234\235\351\230\263"
  3: 100000
}

我们大致知道哪个字段是字符串,哪个字段是数字,然后可以写出这样的proto文件

syntax="proto3";
package test;
message Item {
    string field1=1;
    int32 field2=2;
    int32 field3=3;
    Obj field4=4;

    message Obj {
        string field1=1;
        string field2=2;
        int32 field3=3;
    }
}

命名为person.proto

接着,生成php代码

protoc --php_out=./ person.proto

接着,写反序列化代码

<?php
require_once __DIR__ . '/../../vendor/autoload.php';
include 'GPBMetadata/Person.php';
include 'Test/Item.php';
include 'Test/Item/Obj.php';

//反序列化
$bindata = file_get_contents('./data.bin');
$person = new Test\Item();
$person->mergeFromString($bindata);
echo $person->serializeToJsonString();

最后,运行代码,输出

{"field1":"张三","field2":28,"field3":1,"field4":{"field1":"北京","field2":"朝阳","field3":100000}}

这就清晰多了,字段的值也看到了,再次修改person.proto文件,把字段改成更有意义的

常用命令

protoc --php_out=./ person.proto

protoc --decode_raw < data.bin 

应用场景

  • 直播平台的弹幕
  • 用到json的地方都可以用,比如接口的响应数据

参考

https://www.jianshu.com/p/ce098058edf0

https://developers.google.com/protocol-buffers

https://github.com/protocolbuffers/protobuf/tree/main/php

广而告之,我的新作品《语音助手》上架Google Play了,欢迎下载体验