centraldesktop/protobuf-php

PHP语言的Google协议缓冲区实现


README

Protobuf for PHP是Google协议缓冲区在PHP语言中的实现,支持其二进制数据序列化,包括一个protoc插件,可以从.proto文件生成PHP类。

在生成包含各种类型提示的PHP文件方面投入了大量精力,以帮助IDE进行自动完成。因此,它不仅可以用于与协议缓冲区服务通信,还可以作为任何最终序列化方式的数据对象生成工具。

有关更多信息,请参阅包含的man页面

要求

  • PHP 5.3
  • Pear的Console_CommandLine(用于protoc包装工具)
  • Google的protoc编译器版本2.3或以上
  • GMP或BC Math扩展¹

¹ 仅在int32int64fixed64类型中的负值时需要。请参阅已知问题部分。

功能

工作

  • 标准类型(数字、字符串、枚举、消息等)
  • 扩展、未知和打包字段
  • 生成服务接口
  • Protoc编译器插件以生成PHP类
  • 基于模板的代码生成。尽情发挥并自定义生成的代码 :)
  • 在生成的文件中包含.proto文件的注释
  • 可插拔的序列化后端(编解码器)
    • 标准二进制
    • 标准TextFormat ¹
    • PhpArray
    • JSON
    • ProtoJsonTagMapIndexed变体)
    • XML
  • 反射能力
  • 支持带有注解的动态消息(无需代码生成步骤)
  • 延迟解码消息以在现实世界场景中提高性能

¹ 仅在此编解码器中支持序列化

未来

  • 代码生成速度优化模式

示例用法

$person = new Tutorial\Person();
$person->name = 'DrSlump';
$person->setId(12);

$book = new Tutorial\AddressBook();
$book->addPerson($person);

// Use default codec
$data = $book->serialize();

// Use custom codec
$codec = new \DrSlump\Protobuf\Codec\Json();
$data = $codec->encode($book);
// ... or ...
$data = $book->serialize($codec);

安装

composer install

已知问题

类型

PHP在处理数字方面非常弱。已应用了多种解决方案,以减少协议缓冲区类型和PHP类型之间的不兼容性。

  • Protobuf使用IEEE 754标准存储浮点值,对于double类型使用64位字,对于float类型使用32位。PHP原生支持IEEE 754,尽管精度依赖于平台,但通常支持64位双精度浮点数。这意味着如果您的PHP是用64位大小的双精度浮点数(或更高)编译的,您应该没有问题使用Protobuf编码和解码浮点型和双精度型值。

  • 整数值在PHP中也是平台依赖的。该库是在针对用64位整数编译的PHP二进制文件进行开发和测试的。理论上,无论PHP是否使用32位或64位整数,编码和解码算法都应该正常工作,只需注意,如果使用32位整数,则数字不能超过任何情况下PHP_INT_MAX值(2147483647)。

    尽管Protobuf支持无符号整数,但PHP不支持。事实上,超出编译后的PHP最大整数值(PHP_INT_MAX,64位为0x7FFFFFFFFFFFFFFF)的数字将被自动转换为浮点数,这通常提供53位的十进制精度,允许安全地处理高达0x20000000000000(2^53)的数字,即使它们在PHP中作为浮点数而不是整数表示。更高的数字会丢失精度,甚至可能返回无穷大值,请注意,库不包含对这些数字的任何检查,使用它们可能会产生意外的行为。

    当将负值编码为int32int64fixed64类型时,需要PHP环境中提供大整数扩展GMPBC Math(仅适用于64位架构)。原因是,在编码这些负数时不使用zigzag,二进制表示使用最高位作为符号位,因此这些数字超过了PHP支持的值。库将检查这些条件,并自动尝试使用GMP或BC来处理值。

字符串

二进制编解码器期望字符串使用UTF-8编码。PHP原生不支持字符串编码,PHP的字符串数据类型基本上是长度定界的字节流,因此将自动编码转换包含到库的编码和解码例程中并不是简单的事情。而不是尝试猜测或提供编码配置界面,二进制编解码器将像处理byte类型一样处理string类型,将编码或解码的任务委托给应用程序以所需的字符集执行。

内存使用

由于库的建模方式不允许将消息作为流进行解析或序列化,大型消息可能会很麻烦,整个操作是在内存中完成的,这允许更快的处理,但如果消息太大,可能会消耗过多的RAM。

未知字段

由于不同编解码器的格式中的wire类型不同,因此无法将一个编解码器中消耗的未知字段转码到另一个编解码器。这意味着,例如,当使用二进制编解码器处理消息时,如果它包含未知字段,则在使用Json编解码器序列化消息时,它们将不会包含在内。

生成PHP类

生成工具设计为作为protoc插件运行,因此它应该与官方编译器支持的任何proto文件一起工作。

protoc --plugin=protoc-gen-php --php_out=./build tutorial.proto

要使用proto文件中的非标准选项(如php.namespace),您必须导入库中包含的php.proto文件。其位置将取决于您安装此库的位置。

protoc -I=./Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos \
       --plugin=protoc-gen-php --php_out=./build tutorial.proto

为了使您的生活更轻松,提供的protoc插件提供了一种额外的执行模式,在该模式下,它充当protoc调用的包装器。它将自动包含php.proto路径,因此您不必担心它。

protoc-gen-php -o ./build tutorial.proto

测试

mkdir -p test/generated ./protoc-gen-php.php -o test/generated -Dmultifile=true -i ./test/library/DrSlump/Protobuf/Test/protos/ ./test/library/DrSlump/Protobuf/Test/protos/*.proto ./vendor/bin/phpunit