PHP
ProtocolBuffers

[PHP] PHPでProtocolBuffers

More than 1 year has passed since last update.


■概要

PHPでProtocolBuffersを使用した事例があまりないので導入メモ。

オートローダーとしてcomposerを使用する。


■環境

Windows 7

CentOS 7.4

ProtocolBuffers 3.5.

PHP 7.2.2


■composer設定

CentOSでの作業。


作業ディレクトリ作成

[~]$ mkdir protocol_buffers

[~]$ cd protocol_buffers


composerダウンロード

[protocol_buffers]$ curl -s https://getcomposer.org/installer | php

lsでcomposer.pharがあることを確認。


composer.json作成

[protocol_buffers]$ vi composer.json

{

"name": "google/protobuf",
"type": "library",
"description": "proto library for PHP",
"keywords": ["proto"],
"homepage": "https://developers.google.com/protocol-buffers/",
"license": "BSD-3-Clause",
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": ">=4.8.0"
},
"autoload": {
"psr-4": {
"Google\\Protobuf\\": "src/Google/Protobuf",
"GPBMetadata\\Google\\Protobuf\\": "src/GPBMetadata/Google/Protobuf",
"": "tests/generated",
"GPBMetadata\\": "src/GPBMetadata/",
"MasterData\\": "src/MasterData/"
}
}
}


autoload.php生成

[protocol_buffers]$ php composer.phar dump-autoload

protocol_buffersフォルダ直下にvenderフォルダが生成される。

protocol_buffersを使用するソースでvender/autoload.phpをrequireして使用する。


■ProtocolBuffers設定

WindowsとCentOSでの作業。


ProtocolBuffersソース配置

以下のソースをダウンロード。

https://github.com/google/protobuf/archive/master.zip

protobuf-master\php の srcフォルダをprotocol_buffersフォルダ直下にコピー。


■スキーマファイルのコンパイル

Windowsでの作業。


スキーマファイルの作成

以下の内容でスキーマファイルweapon_master_data.protoを作成。

syntax = "proto3";

package MasterData;
message Weapon {
int32 id = 1;
string name = 2;
double damage = 3;
int32 sell = 4;
}
message WeaponMaster {
repeated Weapon records = 1;
}


スキーマファイルをコンパイル

コンパイラ(protoc.exe)の準備

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

 2018/02/02時点では「protoc-3.5.1-win32.zip」が対象。

 protoc-3.5.1-win32.zip\bin\にprotoc.exeがある。

コンパイル

 protoc.exe のあるフォルダにweapon_master_data.protoを置いて

protoc -I=. --php_out=. weapon_master_data.proto

 以下のファイルがフォルダと共に生成される。

  GPBMetadata\WeaponMasterData.php

  MasterData\Weapon.php

  MasterData\WeaponMaster.php


■コンパイルしたファイルの配置

WindowsとCentOSでの作業。

GPBMetadata\WeaponMasterData.phpをCentOSのprotocol_buffers\src\GPBMetadata\に配置。

MasterDatafフォルダをCentOSのprotocol_buffers\src\に配置。


■テストコード

CentOSでの作業。


シリアライズしたデータの書き込み

[protocol_buffers]$ vi save_test.php

<?php

$autoloader = require_once "vendor/autoload.php";

// Weaponクラス配列
$weaponList = null;

// WeaponMasterクラス生成
$weaponMaster = new MasterData\WeaponMaster();
// repeated fieldsを使用する際にはgetterを使用する。
$records = $weaponMaster->getRecords();

// テストデータ作成
for ($i = 0; $i < 10; $i++)
{
$weaponList[] = array(
'id' => $i,
'name' => "WEAPON_{$i}",
'damage' => $i + 100,
'sell' => $i + 1000
);
}

// 入力パラメータを登録
foreach ($weaponList as $dt)
{
// Weaponクラス生成
$weapon = new MasterData\Weapon();
// パラメータ登録
$weapon->setId($dt['id']);
$weapon->setName($dt['name']);
$weapon->setDamage($dt['damage']);
$weapon->setSell($dt['sell']);

// Weaponクラス配列に登録
$records[] = $weapon;
}

// WeaponMaserクラスに登録
$weaponMaster->setRecords($records);

// シリアライズ
$packed = $weaponMaster->serializeToString();

// バイナリファイル出力
file_put_contents("weapon_data.bin", $packed);


シリアライズデータを読み込んでデシリアライズ

[protocol_buffers]$ vi load_test.php

<?php

$autoloader = require_once "vendor/autoload.php";

// WeaponMasterクラス生成
$weaponMaster = new MasterData\WeaponMaster();

// バイナリファイル読み込み
$filename = "weapon_data.bin";
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);

// デシリアライズ
$weaponMaster->mergeFromString($contents);

// デバッグプリント
$records = $weaponMaster->getRecords();
foreach ($records as $rec)
{
$id = $rec->getId();
$name = $rec->getName();
$damage = $rec->getDamage();
$sell = $rec->getSell();

print_r("id:{$id}, name:{$name}, damage:{$damage}, sell:{$sell}\n");
}


■実行

CentOSでの作業。


シリアライズ

[protocol_buffers]$ php save_test.php

weapon_data.binが出力される。

以下のようなエラーが出る場合、PHPのバージョンが古い。

PHP Parse error:  syntax error, unexpected T_CLASS, expecting T_STRING or T_VARIABLE or '$' in /home/xxx/protocol_buffers/src/MasterData/WeaponMaster.php on line 42


デシリアライズ

[protocol_buffers]$ php load_test.php

実行結果

id:0, name:WEAPON_0, damage:100, sell:1000

id:1, name:WEAPON_1, damage:101, sell:1001
id:2, name:WEAPON_2, damage:102, sell:1002
id:3, name:WEAPON_3, damage:103, sell:1003
id:4, name:WEAPON_4, damage:104, sell:1004
id:5, name:WEAPON_5, damage:105, sell:1005
id:6, name:WEAPON_6, damage:106, sell:1006
id:7, name:WEAPON_7, damage:107, sell:1007
id:8, name:WEAPON_8, damage:108, sell:1008
id:9, name:WEAPON_9, damage:109, sell:1009


■テストコード置き場と実行方法


作業ディレクトリ作成

[~]$ mkdir sample;

[~]$ cd sample;


githubからリポジトリ取得

[sample]$ git clone https://github.com/kflower725/sample_program.git


protocol_buffersフォルダに移動

[sample]$ cd sample_program/protocol_buffers/


実行

[protocol_buffers]$ php load_test.php 

実行結果

id:0, name:WEAPON_0, damage:100, sell:1000

id:1, name:WEAPON_1, damage:101, sell:1001
id:2, name:WEAPON_2, damage:102, sell:1002
id:3, name:WEAPON_3, damage:103, sell:1003
id:4, name:WEAPON_4, damage:104, sell:1004
id:5, name:WEAPON_5, damage:105, sell:1005
id:6, name:WEAPON_6, damage:106, sell:1006
id:7, name:WEAPON_7, damage:107, sell:1007
id:8, name:WEAPON_8, damage:108, sell:1008
id:9, name:WEAPON_9, damage:109, sell:1009


■参考

[PHP]ComposerでAutoload出来ない時の確認方法