PHP
FlatBuffers

[PHP] PHPでFlatBuffers

More than 1 year has passed since last update.


■概要

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


■環境

CentOS 7.4

PHP 5.4.16

flatbuffers 1.8.0


■flatcのビルド

githubからFlatBuffersのファイルを取得。

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

flatbuffersフォルダに移動。

$ cmake -G "Unix Makefiles"     

$ make
$ sudo make install

flatbuffersフォルダにflatcが生成されていることを確認。


メモ

CentOS 7.4/gcc 4.8.5だと問題なくビルドが行えたが、CentOS 6.2/gcc 4.4.7ではビルドできなかった。

ビルドできなかった詳細としては、make時にstd::stringのpop_backが無いなどのエラーが発生、CMakeList.txtで-std=c++0xのオプションが設定されているのは確認したがエラー発生の原因は不明。gccの新しいバージョンを使用するにもCentOS 6.2だとgccが4.4.7までしかバージョンアップできなったためCentOS 7.4を使用。


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

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

namespace MyGame;    

table Monster {
hp:int;
name:string;
}

以下のコマンドでコンパイル。

flatc --php monster.fbs

monster.fbsのスキーマで定義されているnamespace名「MyGame」でフォルダが作成され、そのフォルダ内にテーブル名「Monster.php」でファイルが作成される。


MyGame/Monster.php

<?php

// automatically generated by the FlatBuffers compiler, do not modify

namespace MyGame;

use \Google\FlatBuffers\Struct;
use \Google\FlatBuffers\Table;
use \Google\FlatBuffers\ByteBuffer;
use \Google\FlatBuffers\FlatBufferBuilder;

class Monster extends Table
{
/**
* @param ByteBuffer $bb
* @return Monster
*/
public static function getRootAsMonster(ByteBuffer $bb)
{
$obj = new Monster();
return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
}

/**
* @param int $_i offset
* @param ByteBuffer $_bb
* @return Monster
**/
public function init($_i, ByteBuffer $_bb)
{
$this->bb_pos = $_i;
$this->bb = $_bb;
return $this;
}

/**
* @return int
*/
public function getHp()
{
$o = $this->__offset(4);
return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
}

public function getName()
{
$o = $this->__offset(6);
return $o != 0 ? $this->__string($o + $this->bb_pos) : null;
}

/**
* @param FlatBufferBuilder $builder
* @return void
*/
public static function startMonster(FlatBufferBuilder $builder)
{
$builder->StartObject(2);
}

/**
* @param FlatBufferBuilder $builder
* @return Monster
*/
public static function createMonster(FlatBufferBuilder $builder, $hp, $name)
{
$builder->startObject(2);
self::addHp($builder, $hp);
self::addName($builder, $name);
$o = $builder->endObject();
return $o;
}

/**
* @param FlatBufferBuilder $builder
* @param int
* @return void
*/
public static function addHp(FlatBufferBuilder $builder, $hp)
{
$builder->addIntX(0, $hp, 0);
}

/**
* @param FlatBufferBuilder $builder
* @param StringOffset
* @return void
*/
public static function addName(FlatBufferBuilder $builder, $name)
{
$builder->addOffsetX(1, $name, 0);
}

/**
* @param FlatBufferBuilder $builder
* @return int table offset
*/
public static function endMonster(FlatBufferBuilder $builder)
{
$o = $builder->endObject();
return $o;
}
}


■テストコード


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

<?php

// flatbuffersファイル
require_once("php/ByteBuffer.php");
require_once("php/Constants.php");
require_once("php/FlatbufferBuilder.php");
require_once("php/Struct.php");
require_once("php/Table.php");

// スキーマファイルをコンパイルしたファイル
require_once("MyGame/Monster.php");

// バッファ生成
$builder = new Google\FlatBuffers\FlatBufferBuilder(1);

// モンスターパラメータ取得
$monster_name = $builder->createString("Ork");
$monster_hp = 10;

// モンスター構築開始
MyGame\Monster::startMonster($builder);
// モンスターパラメータ設定
MyGame\Monster::addName($builder, $monster_name);
MyGame\Monster::addHp($builder, $monster_hp);
// モンスター構築終了
$monster_offset = MyGame\Monster::EndMonster($builder);

// バッファ生成終了
$builder->finish($monster_offset);

// バイナリファイル出力
file_put_contents("monster_data.bfbs", $builder->sizedByteArray());


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

<?php

// flatbuffersファイル
require_once("php/ByteBuffer.php");
require_once("php/Constants.php");
require_once("php/FlatbufferBuilder.php");
require_once("php/Struct.php");
require_once("php/Table.php");

// スキーマファイルをコンパイルしたファイル
require_once("MyGame/Monster.php");

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

// 読み込んだ生データからByteBufferを生成
$bytebuffers = Google\FlatBuffers\ByteBuffer::wrap($contents);

// デシリアライズオブジェクトを取得
$monster = MyGame\Monster::GetRootAsMonster($bytebuffers);

// パラメータ取得
$hp = $monster->getHp();
$name = $monster->getName();

// デバッグ出力
echo "hp:{$hp}, name:{$name}\n";


メモ

require_onceで読み込んでいるファイルはFlatBuffersの以下のコード。

https://github.com/google/flatbuffers/tree/master/php


■参考

flatcリファレンス

Use in PHP

FlatBuffersをPHPで使ってみる