PHP中使用Protobuf简介


点击访问原文
您还可以加入全栈技术交流群(QQ群号:254842154)


protobuf简介

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前只提供了 C++、Java、Python 三种语言的 API。

官方不支持PHP,不用担心,高手在民间。上Github搜索一下就有了。

安装protobuf

wget http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.bz2
tar -jxvf protobuf-2.4.1.tar.bz2 
cd protobuf-2.4.1/
./configure
make
make install

查看protobuf版本

protoc --version

编译php的protobuf扩展

在Google上搜索 protobuf php 可在github上找到两个与之相关的开源项目,它们是:

https://github.com/allegro/php-protobuf
https://github.com/drslump/Protobuf-PHP

在这里主要介绍allegro的编译方法(别问为什么,因为drslump的编译方法在我的电脑上不成功 -_- ||)。

下面介绍centos(CentOS Linux release 7.0.1406 (Core))环境中下载,编译:

wget https://github.com/allegro/php-protobuf/archive/master.zip
unzip master.zip
cd php-protobuf-master

安装依赖

yum install php-devel

假如phpize不在默认目录,可以使用 which phpize查看,然后写全路径去执行phpize,我这里是默认在 /usr/bin目录,可以直接执行,执行之后可以看到以下输出

[root@VM_18_199_centos php-protobuf-master]# phpize
Configuring for:
PHP Api Version:         20100412
Zend Module Api No:      20100525
Zend Extension Api No:   220100525

php-config的目录也使用which php-config这个命令去查看路径,这一步需要安装gcc

yum -y install gcc-c++

安装完gcc之后则开始正式安装pb

./configure
make
make install

最后会看到类似这样的安装提示,则说明安装成功。

[root@VM_18_199_centos php-protobuf-master]# make install
Installing shared extensions:     /usr/lib64/php/modules/

现已成功把pb编译至/usr/lib64/php/modules/protobuf.so

开启php的pb扩展

找到php.in,加入这行代码:

extension=/usr/lib64/php/modules/protobuf.so

重启nginx

/usr/sbin/nginx -s reload

//重启php-fpm
kill -SIGUSR2 `cat /run/php-fpm/php-fpm.pid`

假如是Apache,则重启Apache

//centos 7.0
systemctl restart httpd
//centos 6.5
service httpd restart

编译proto文件

新建一个简单的proto文件:

vim test.proto

输入以下内容:

message PhoneNumber {
    required string number = 1;
    required int32 type = 2;
}

message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
    repeated PhoneNumber phone = 4;
    optional double money = 5;
}

message AddressBook {
  repeated Person person = 1;
}

编译。注意,这里需要引用到protoc-php.php这个文件,注意路径。

php ./php-protobuf-master/protoc-php.php  test.proto

编译成功后会在当前目录生成一个pb_proto_test.php文件,内容如下:

 /**
 * Auto generated from test.proto at 2015-10-22 23:19:46
 */

/**
 * PhoneNumber message
 */
class PhoneNumber extends \ProtobufMessage
{
    /* Field index constants */
    const NUMBER = 1;
    const TYPE = 2;

    /* @var array Field descriptors */
    protected static $fields = array(
        self::NUMBER => array(
            'name' => 'number',
            'required' => true,
            'type' => 7,
        ),
        self::TYPE => array(
            'name' => 'type',
            'required' => true,
            'type' => 5,
        ),
    );

    /**
     * Constructs new message container and clears its internal state
     *
     * @return null
     */
    public function __construct()
    {
        $this->reset();
    }
    
    .......
    
}

这里会继承ProtobufMessage类,它是在protobuf.so中自动加载的。
写一个测试类来测试一下:

<?php
require_once 'pb_proto_test.php';

$foo = new Person();
$foo->setName('hellojammy');
$foo->setId(2);
$foo->setEmail('helloxxx@foxmail.com');
$foo->setMoney(1988894.995);

$phone_num = new PhoneNumber();
$phone_num->setNumber('1351010xxxx');
$phone_num->setType(3);

$foo->appendPhone($phone_num);
//$foo->appendPhone(2);
$packed = $foo->serializeToString();
//echo $packed;exit;
#$foo->clear();
echo "-----------src------------\n";
echo $foo->getName() ."\n";
echo $foo->getPhone()[0]->getNumber() ."\n";
$foo->dump();
echo "------------------------\n\n\n";


try {
      $p = new Person();
      $p->parseFromString($packed);
      echo "------------parsed-------\n";
      echo $p->getName() ."\n";
      echo $p->getEmail() ."\n";
      echo $p->getMoney() ."\n";
      echo $p->getId() . "\n";
      echo $p->getPhone()[0]->getNumber() ."\n";

      //$p->dump();
      echo "------------------------\n";
      //print_r($xiao);
      } catch (Exception $ex) {
      die('Upss.. there is a bug in this example');
}

运行

php text.php

可以看到输出:

-----------src------------
hellojammy
1351010xxxx
Person {
  1: name => 'hellojammy'
  2: id => 2
  3: email => 'helloxxx@foxmail.com'
  4: phone(1) =>
    [0] =>
      PhoneNumber {
        1: number => '1351010xxxx'
        2: type => 3
      }
  5: money => 1988894.995
}
------------------------


------------parsed-------
hellojammy
helloxxx@foxmail.com
1988894.995
2
1351010xxxx
------------------------
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容