forget for get

覚えるために忘れる

FlatBuffersチュートリアル(日本語)PHP

公式ドキュメントが英語で、日本語の情報があまりみつからないので、やってみてまとめます。
公式チュートリアルは1ファイルで書き読みやってるけど、今回は書き・読み2ファイルに分けます。

 

FlatBuffersとは

Google社が開発しているクロスプラットフォーム対応のシリアライゼーションライブラリ。
Jsonと違い、パースやunpackingが不要でデータにアクセスできるので高速。
Cocos2d-x、FacebookAndroidアプリなどで使われている。

https://google.github.io/flatbuffers/index.html

 

環境

centos8、PHP7.4

 

作業ディレクトリ作成

mkdir fbwork
cd fbwork

 

FlatBuffersをクローン

git clone https://github.com/google/flatbuffers.git

flatbuffers/php/下にphp用のライブラリがある

flatc(FlatBuffersのコンパイラ)をビルド(初回のみ)

yum install gcc-c++ cmake
cd flatbuffers
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
make
ln -s /flatbuffersのフルパス/flatc /usr/local/bin/flatc
cd ../

スキーマを作成

vi monster.fbs

namespace MyGame.Sample;
enum Color:byte { Red = 0, Green, Blue = 2 }
struct Vec3 {
  x:float;
  y:float;
  z:float;
}
table Monster {
  pos:Vec3;
  hp:short = 100;
  name:string;
  color:Color = Blue;
  weapons:[Weapon];
}
table Weapon {
  name:string;
  damage:short;
}
root_type Monster;

 スキーマコンパイル

flatc --php monster.fbs

MyGame/Sample/以下にファイルが作成される
Color.php Monster.php Vec3.php Weapon.php

 

書き込みサンプル

vi WriteSample.php

<?php
function __autoload($class_name) {
  $class = substr($class_name, strrpos($class_name, "\\") + 1);
  $root_dir = dirname(__FILE__);
  $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "flatbuffers", "php")),
                 join(DIRECTORY_SEPARATOR, array($root_dir, "MyGame", "Sample")));
  foreach ($paths as $path) {
    $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
    if (file_exists($file)) {
      require($file);
      break;
    }
  }
}

$builder = new \Google\FlatBuffers\FlatbufferBuilder(1024);

$weapon_one_name = $builder->createString("Sword");
$sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one_name, 3);
$weapon_two_name = $builder->createString("Axe");
$axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two_name, 5);

$weaps = array($sword, $axe);
$weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);

$name = $builder->createString("Orc");

$pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);

\MyGame\Sample\Monster::StartMonster($builder);
\MyGame\Sample\Monster::AddPos($builder, $pos);
\MyGame\Sample\Monster::AddHp($builder, 300);
\MyGame\Sample\Monster::AddName($builder, $name);
\MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red);
\MyGame\Sample\Monster::AddWeapons($builder, $weapons);
$orc = \MyGame\Sample\Monster::EndMonster($builder);

$builder->finish($orc);
file_put_contents("monster.dat", $builder->sizedByteArray());

 

php WriteSample.phpと実行すると、バイナリファイル(monster.dat)が生成される。

読み込みサンプル

vi ReadSample.php

<?php
function __autoload($class_name) {
  $class = substr($class_name, strrpos($class_name, "\\") + 1);
  $root_dir = dirname(__FILE__);
  $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "flatbuffers", "php")),
                 join(DIRECTORY_SEPARATOR, array($root_dir, "MyGame", "Sample")));
  foreach ($paths as $path) {
    $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
    if (file_exists($file)) {
      require($file);
      break;
    }
  }
}

$contents = file_get_contents("monster.dat");
$bb = \Google\FlatBuffers\ByteBuffer::wrap($contents);

$monster = \MyGame\Sample\Monster::GetRootAsMonster($bb);

echo $monster->getHp() . "\n";
echo $monster->getName() . "\n";
echo $monster->getColor() . "\n";
echo $monster->getPos()->getX() . "\n";
echo $monster->getPos()->getY() . "\n";
echo $monster->getPos()->getZ() . "\n";

 

php ReadSample.phpと実行すると、バイナリファイル(monster.dat)を読み込んだ結果を表示します。

 

FlatBufferバイナリをJSONにパース

flatc --json --raw-binary monster.fbs -- monster.dat

JSONファイル(monster.json)が生成される

 

参考

公式チュートリアル

https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html

FlatBuffersをPHPで使ってみる

https://labs.gree.jp/blog/2015/11/14495/