Реализация google protocol buffers на php
phpbuf – реализация google protocol buffers на php.
Эта библиотека не имеет пока генераторов кода. Классы сообщений нужно писать самому. Благо что пишутся они очень просто.
Установка
Просто копируете содержимое папки lib в удобное для Вас место. Потом подключаете файл PhpBuf.php
require_once("PhpBuf.php");
Классы сообщений
Классы сообщений наследуются от класса PhpBuf_Message_Abstract, в конструкторе описывается структура. Например, класс:
class Message_Example extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("id", PhpBuf_Type::INT, PhpBuf_Rule::REQUIRED, 1);
$this->setField("balance", PhpBuf_Type::SINT, PhpBuf_Rule::REQUIRED, 2);
$this->setField("isAdmin", PhpBuf_Type::BOOL, PhpBuf_Rule::REQUIRED, 3);
$this->setField("status", PhpBuf_Type::ENUM, PhpBuf_Rule::REQUIRED, 4, array("active", "inactive", "deleted"));
$this->setField("name", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 5);
$this->setField("bytes", PhpBuf_Type::BYTES, PhpBuf_Rule::REQUIRED, 6);
}
}
public function __construct() {
$this->setField("id", PhpBuf_Type::INT, PhpBuf_Rule::REQUIRED, 1);
$this->setField("balance", PhpBuf_Type::SINT, PhpBuf_Rule::REQUIRED, 2);
$this->setField("isAdmin", PhpBuf_Type::BOOL, PhpBuf_Rule::REQUIRED, 3);
$this->setField("status", PhpBuf_Type::ENUM, PhpBuf_Rule::REQUIRED, 4, array("active", "inactive", "deleted"));
$this->setField("name", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 5);
$this->setField("bytes", PhpBuf_Type::BYTES, PhpBuf_Rule::REQUIRED, 6);
}
}
соответствует .proto файлу:
message Message_Example {
required int32 id = 1;
required sint32 balance = 2;
required bool isAdmin = 3;
enum Status {
active = 0;
inactive = 1;
deleted = 2;
}
required enum Status status = 4;
required string name = 5;
required bytes bytes = 6;
}
required int32 id = 1;
required sint32 balance = 2;
required bool isAdmin = 3;
enum Status {
active = 0;
inactive = 1;
deleted = 2;
}
required enum Status status = 4;
required string name = 5;
required bytes bytes = 6;
}
Вызов метода setField() создает атрибут объекта с определенным типом. Метод принимает пять параметров: protected function setField($name, $type, $rule, $index, $extra = "")
$name– определяет имя атрибута$type– определяет тип атрибута. Тип атрибута задается обычно константой определенной в классеPhpBuf_Type. На сегодняшний момент поддерживаются 7 типов: bool (PhpBuf_Type::BOOL), bytes (PhpBuf_Type::BYTES), int32 (PhpBuf_Type::INT), sint32 (PhpBuf_Type::SINT), string (PhpBuf_Type::STRING), enum (PhpBuf_Type::ENUM) и message (PhpBuf_Type::MESSAGE)$rule– определяет правила для сериализации и десериализации атрибута. Их три:PhpBuf_Rule::REQUIRED,PhpBuf_Rule::REPEAREDиPhpBuf_Rule::OPTIONAL. Обычно задается одной из этих констант.$index– определяет индекс атрибута (необходим для сериализации и десериализации).$extra– определяет дополнительные параметры. Используется в двух случаях: когда тип атрибутаPhpBuf_Type::ENUM, нужно передать массив возможных значений для перечисляемого типа; и когда тип атрибутаPhpBuf_Type::MESSAGE, тогда надо передать имя класса сообщения.
Подробнее о типах и правилах можете прочитать на странице проекта google protocol buffers
message SearchResponse {
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
class Result extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("url", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 1);
$this->setField("title", PhpBuf_Type::STRING, PhpBuf_Rule::OPTIONAL, 2);
$this->setField("snippets", PhpBuf_Type::STRING, PhpBuf_Rule::REPEATED, 3);
}
}
class SearchResponse extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("result", PhpBuf_Type::MESSAGE, PhpBuf_Rule::REPEATED, 1, "Result");
}
}
public function __construct() {
$this->setField("url", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 1);
$this->setField("title", PhpBuf_Type::STRING, PhpBuf_Rule::OPTIONAL, 2);
$this->setField("snippets", PhpBuf_Type::STRING, PhpBuf_Rule::REPEATED, 3);
}
}
class SearchResponse extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("result", PhpBuf_Type::MESSAGE, PhpBuf_Rule::REPEATED, 1, "Result");
}
}
Пример использования
class Request extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("query", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 1);
}
}
class Result extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("url", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 1);
$this->setField("title", PhpBuf_Type::STRING, PhpBuf_Rule::OPTIONAL, 2);
$this->setField("snippets", PhpBuf_Type::STRING, PhpBuf_Rule::REPEATED, 3);
}
}
class SearchResponse extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("result", PhpBuf_Type::MESSAGE, PhpBuf_Rule::REPEATED, 1, "Result");
}
}
$rawData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : @file_get_contents("php://input");
$request = new Request();
$request->read(new PhpBuf_IO_Reader($rawData));
$result = doSomethingQuery($request->query);
$response = new SearchResponse();
$arrayResult = array();
foreach($result as $item) {
$result = new Result;
$result->url = $item['url'];
if(isset($item['title']) && !empty($item['title'])) {
$result->title = $item['title'];
}
if(isset($item['snippets']) && !empty($item['snippets'])) {
$result->snippets = $item['snippets'];
}
$arrayResult[] = $result;
}
$response->result = $arrayResult;
$writer = new PhpBuf_IO_Writer();
$response->write($writer);
header("Content-type: application/octet-stream");
echo $writer->getData();
exit;
?>
public function __construct() {
$this->setField("query", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 1);
}
}
class Result extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("url", PhpBuf_Type::STRING, PhpBuf_Rule::REQUIRED, 1);
$this->setField("title", PhpBuf_Type::STRING, PhpBuf_Rule::OPTIONAL, 2);
$this->setField("snippets", PhpBuf_Type::STRING, PhpBuf_Rule::REPEATED, 3);
}
}
class SearchResponse extends PhpBuf_Message_Abstract {
public function __construct() {
$this->setField("result", PhpBuf_Type::MESSAGE, PhpBuf_Rule::REPEATED, 1, "Result");
}
}
$rawData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : @file_get_contents("php://input");
$request = new Request();
$request->read(new PhpBuf_IO_Reader($rawData));
$result = doSomethingQuery($request->query);
$response = new SearchResponse();
$arrayResult = array();
foreach($result as $item) {
$result = new Result;
$result->url = $item['url'];
if(isset($item['title']) && !empty($item['title'])) {
$result->title = $item['title'];
}
if(isset($item['snippets']) && !empty($item['snippets'])) {
$result->snippets = $item['snippets'];
}
$arrayResult[] = $result;
}
$response->result = $arrayResult;
$writer = new PhpBuf_IO_Writer();
$response->write($writer);
header("Content-type: application/octet-stream");
echo $writer->getData();
exit;
?>
