Protocol Buffer学习笔记(PHP)

摘要

项目中引入proto的依赖

在项目根目录下执行如下命令,composer会自动下载最新版本,目前是"google/protobuf": “^3.5”
composer require "google/protobuf"

准备proto文件

  • 注意事项参考:PHP Generated Code

  • proto示例文件参考Protocol Buffer学习笔记(Java&NodeJS),这里注意去掉其中的requiredoptional,因为这里要求语法严格遵循proto3,不能在属性前出现requiredoptional,所以文件顶端要明确syntax = "proto3";,另外增加package配置为package app.proto;

生成proto对应的php文件

  • 将准备好的proto文件放到laravel根目录下,并在根目录下执行如下命令
    protoc --php_out=. OTIpcDef.proto

  • 此时会在app目录下自动创建Proto目录,并在其目录下生成对应的php类文件

  • 同时在根目录下会生成GPBMetadata\OTIpcDef.php

  • 由于laravel要求所有的class都必须在app目录下,所以需要移动GPBMetadata目录到app目录下,同时修改对应的namespace 为namespace App\GPBMetadata;;

  • 同时需要修改app\Proto下的各个class的构造方法

1
2
3
4
public function __construct() {
\App\GPBMetadata\OTIpcDef::initOnce();
parent::__construct();
}

php中使用protobuf

创建ProtoController

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace App\Http\Controllers;
use App\Proto\BaseInfoCompany;
use App\Helper\HttpUtils;

class ProtoController extends Controller
{
/**
* ProtoController constructor.
*/
public function __construct()
{
}
}

1.主动获取protobuf数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public function build_proto_data()
{
$baseInfoCompany = new BaseInfoCompany();
$baseInfoCompany->setAddress(110011);
$baseInfoCompany->setCompanyId("companyId");
$baseInfoCompany->setCompanyName("companyName中文");
$baseInfoCompany->setIdentifier("identifier");
$baseInfoCompany->setBusinessScope("BusinessScope");
$baseInfoCompany->setContactAddress("ContactAddress");
$baseInfoCompany->setEconomicType("EconomicType");
$baseInfoCompany->setRegCapital("RegCapital");
$baseInfoCompany->setLegalName("LegalName");
$baseInfoCompany->setLegalID("LegalID");
$baseInfoCompany->setLegalPhone("LegalPhone");
$baseInfoCompany->setState(0);
$baseInfoCompany->setFlag(1);
$baseInfoCompany->setUpdateTime(20180226121212);
// $protostr = $baseInfoCompany->serializeToString();
//生成json
$protostr = $baseInfoCompany->serializeToJsonString();
return $protostr;
}

public function receive_proto_data(){
$protoData = file_get_contents("http://localhost:83/proto/build");
try {
$baseInfoCompany = new BaseInfoCompany();
// $baseInfoCompany->mergeFromString($protoData);
$baseInfoCompany->mergeFromJsonString($protoData);
echo $baseInfoCompany->getCompanyName();

return $baseInfoCompany->serializeToJsonString();
} catch (Exception $ex) {
die('something is wrong');
}
}

2.被动接收protobuf数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public function send_proto_data(){
$data = $this->build_proto_data();
$receive = HttpUtils::request_by_curl("http://localhost:83/proto/receive",$data);
echo $receive;
}

public function receive_proto_data(){
// $protoData = file_get_contents("http://localhost:83/proto/build");
$protoData = $_POST["data"];
try {
$baseInfoCompany = new BaseInfoCompany();
// $baseInfoCompany->mergeFromString($protoData);
$baseInfoCompany->mergeFromJsonString($protoData);
echo $baseInfoCompany->getCompanyName();
return $baseInfoCompany->serializeToJsonString();
} catch (Exception $ex) {
die('something is wrong');
}
}

  • 这里用到一个工具类App\Helper\HttpUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace App\Helper;
class HttpUtils
{

public static function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'data=' . $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_TIMEOUT, 1);//异步处理
$data = curl_exec($ch);
if (curl_errno($ch)) { //响应错误的处理
}
curl_close($ch);
return $data;
}
}