jacknoordhuis/php-protobuf

Google的Protocol Buffers for PHP

v0.12.3 2018-03-14 07:57 UTC

This package is auto-updated.

Last update: 2024-09-14 03:53:37 UTC


README

概述

Protocol Buffers(协议缓冲区)是一种以高效且可扩展的格式编码结构化数据的方法。它可以用于文件格式和RPC协议。

PHP Protobuf是Google为PHP实现的Protocol Buffers,旨在提供高性能,包括一个protoc插件,用于从.proto文件生成PHP类。重负载(解析和序列化)由PHP扩展完成。

要求

  • PHP 7.0或更高版本(对于PHP 5支持,请参阅php5分支)
  • Pear的Console_CommandLine(用于protoc插件)
  • Google的protoc编译器版本2.6或更高

入门指南

安装

  1. 克隆源代码

    git clone https://github.com/allegro/php-protobuf
    
  2. 进入源代码目录

    cd php-protobuf
    
  3. 构建并安装PHP扩展(遵循php.net上的说明)

  4. 安装protoc插件依赖项

    composer install
    

全局Composer安装

  1. 定位您的全局Composer目录(通常是~/.composer)

  2. 将Git仓库添加到composer.json

    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/JackNoordhuis/php-protobuf"
        }
    ]
    
  3. 将库作为全局依赖项添加

    "require": [
       "jacknoordhuis/php-protobuf": "dev-master"
    ]
    
  4. 最后,运行composer global update以安装所需依赖项

  5. 现在您可以从任何位置运行protoc-gen-php命令

用法

  1. 假设您有一个名为foo.proto的文件

    message Foo
    {
        required int32 bar = 1;
        optional string baz = 2;
        repeated float spam = 3;
    }
    
  2. 编译foo.proto

    php protoc-gen-php.php foo.proto
    
  3. 创建Foo消息并填充一些数据

    require_once 'Foo.php';
    
    $foo = new Foo();
    $foo->setBar(1);
    $foo->setBaz('two');
    $foo->appendSpam(3.0);
    $foo->appendSpam(4.0);
  4. 将消息序列化为字符串

    $packed = $foo->serializeToString();
  5. 从字符串解析消息

    $parsedFoo = new Foo();
    try {
        $parsedFoo->parseFromString($packed);
    } catch (Exception $ex) {
        die('Oops.. there is a bug in this example, ' . $ex->getMessage());
    }
  6. 让我们看看我们解析了什么

    $parsedFoo->dump();

    它应该产生类似以下输出的内容

    Foo {
      1: bar => 1
      2: baz => 'two'
      3: spam(2) =>
        [0] => 3
        [1] => 4
    }
    
  7. 如果您愿意,可以重置对象到其初始状态

    $parsedFoo->reset();

指南

编译

PHP Protobuf附带Google的protoc编译器插件。您可以直接运行

php protoc-gen-php.php -o output_dir foo.proto

或将其传递给protoc

protoc --plugin=protoc-gen-allegrophp=protoc-gen-php.php --allegrophp_out=output_dir foo.proto

在Windows上使用protoc-gen-php.bat代替。

命令行选项

  • -o out, --out=out - 生成文件的目标目录(默认为当前目录)。
  • -I proto_path, --proto_path=proto_path - 搜索导入的目录。
  • --protoc=protoc - protoc编译器可执行文件的路径。
  • -D define, --define=define - 定义生成器选项(例如 -Dnamespace='Foo\Bar\Baz')。

生成器选项

  • namespace - 要由生成的PHP类使用的命名空间。

消息类

编译期间生成的类符合PSR-0规范(每个类都放入它自己的文件)。如果没有定义namespace生成器选项,则使用包名(如果存在)来创建命名空间。如果没有设置包名,则将类放入全局空间。

PHP Protobuf模块实现了ProtobufMessage类,该类封装了协议逻辑。从proto文件编译的消息扩展了这个类,提供了消息字段描述符。基于这些描述符,ProtobufMessage知道如何解析和序列化给定类型的消息。

为每个字段生成一组访问器。方法集对于单值字段(required / optional)和多值字段(repeated)不同。

  • required / optional

      get{FIELD}()        // return a field value
      has{FIELD}()        // check whether a field is set
      set{FIELD}($value)  // set a field value to $value
    
  • repeated

      append{FIELD}($value)       // append $value to a field
      clear{FIELD}()              // empty field
      get{FIELD}()                // return an array of field values
      getAt{FIELD}($index)        // return a field value at $index index
      getCount{FIELD}()           // return a number of field values
      has{FIELD}()                // check whether a field is set
      getIterator{FIELD}()        // return an ArrayIterator
    

{FIELD}是驼峰式的字段名。

枚举

PHP 原生不支持枚举类型。因此,枚举类型由 PHP 整数类型表示。为了方便,枚举会被编译成一个类,其中包含对应其可能值的常量集合。

类型映射

可用的内置 PHP 类型范围存在一些限制。PHP 不支持 64 位正整数类型。请注意,解析大整数值可能会导致出现意外结果。

Protocol Buffers 类型映射到 PHP 类型如下(x86_64)

| Protocol Buffers | PHP    |
| ---------------- | ------ |
| double           | float  |
| float            |        |
| ---------------- | ------ |
| int32            | int    |
| int64            |        |
| uint32           |        |
| uint64           |        |
| sint32           |        |
| sint64           |        |
| fixed32          |        |
| fixed64          |        |
| sfixed32         |        |
| sfixed64         |        |
| ---------------- | ------ |
| bool             | bool   |
| ---------------- | ------ |
| string           | string |
| bytes            |        |

Protocol Buffers 类型映射到 PHP 类型如下(x86)

| Protocol Buffers | PHP                         |
| ---------------- | --------------------------- |
| double           | float                       |
| float            |                             |
| ---------------- | --------------------------- |
| int32            | int                         |
| uint32           |                             |
| sint32           |                             |
| fixed32          |                             |
| sfixed32         |                             |
| ---------------- | --------------------------- |
| int64            | if val <= PHP_INT_MAX       |
| uint64           | then value is stored as int |
| sint64           | otherwise as double         |
| fixed64          |                             |
| sfixed64         |                             |
| ---------------- | --------------------------- |
| bool             | bool                        |
| ---------------- | --------------------------- |
| string           | string                      |
| bytes            |                             |

未设置值由 null 类型表示。要取消设置值,只需将其值设置为 null

解析

要解析消息,创建一个消息类实例,并调用其 parseFromString 方法,将序列化消息传递给它。遇到的错误通过抛出 Exception 来指示。异常消息提供了详细的解释。未设置的必需字段被静默忽略。

$packed = /* serialized FooMessage */;
$foo = new FooMessage();

try {
    $foo->parseFromString($packed);
} catch (Exception $ex) {
    die('Parse error: ' . $e->getMessage());
}

$foo->dump(); // see what you got

序列化

要序列化消息,调用 serializeToString 方法。它返回一个包含 protobuf 编码消息的字符串。遇到的错误通过抛出 Exception 来指示。异常消息提供了详细的解释。未设置的必需字段会触发一个错误。

$foo = new FooMessage()
$foo->setBar(1);

try {
    $packed = $foo->serializeToString();
} catch (Exception $ex) {
    die 'Serialize error: ' . $e->getMessage();
}

/* do some cool stuff with protobuf-encoded $packed */

调试

可能存在需要调查给定消息实际内容的情况。在消息实例上 var_dump 提供的结果有些难以理解。

ProtobufMessage 类附带一个 dump 方法,它将消息内容打印到标准输出。它接受一个可选参数,指定是否只想打印已设置的字段(默认情况下,它只打印已设置的字段)。将 false 作为参数传递以打印所有字段。它产生的格式类似于 var_dump

或者,您可以使用 printDebugString() 方法,该方法以协议缓冲区文本格式生成输出。

IDE 辅助工具和自动完成支持

要将此扩展与您的 IDE(PhpStorm、Eclipse 等)集成并获得自动完成支持,只需在项目根目录下任何位置包含 stubs\ProtobufMessage.php 即可。

已知问题

参考文献

致谢