php安装protocol buffer 扩展,thinkphp引入protocol buffer

文章目录

    • protobuf
    • 扩展安装
    • 安装protoc
    • 代码测试
    • thinkPHP中使用protobuf

protobuf

protobuf是一个通信协议,类似json和xml。protobuf反序列化之后体积比他们小,而且序列化和反序列化的性能要比他们高(json不一定 如果protobuf层级太多不一定比json快,一般1-3个层级的情况下几乎都是protobuf比较快)

扩展安装

github地址:

https://github.com/allegro/php-protobuf/

切换到root用户

git clone https://github.com/allegro/php-protobuf

进入php-protobuf目录

cd php-protobuf

安装扩展库

phpize
./configure
make
make install

检查protobuf库是否被安装到扩展目录下

php -i| grep extension_dir

输出扩展目录

extension_dir => /usr/lib64/php/modules => /usr/lib64/php/modules

ll /usr/lib64/php/modules

确认是否有 protobuf.so

-rwxr-xr-x 1 root root  159704 Nov 23 11:15 protobuf.so

如果找不到 make的时候会提示库被安装到哪里了

libtool: install: cp ./.libs/protobuf.so /usr/local/src/php-protobuf/modules/protobuf.so

/bin/sh /usr/local/src/php-protobuf/libtool --mode=install cp ./protobuf.la /usr/local/src/php-protobuf/modules
libtool: install: cp ./.libs/protobuf.so /usr/local/src/php-protobuf/modules/protobuf.so
libtool: install: cp ./.libs/protobuf.lai /usr/local/src/php-protobuf/modules/protobuf.la
libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/mysql/bin/:/usr/local/go/bin:/root/bin:/sbin" ldconfig -n /usr/local/src/php-protobuf/modules
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/src/php-protobuf/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

Build complete.
Don't forget to run 'make test'.

修改配置文件
配置有两种方式 一种是创建 protobuf.ini 文件,一种是接在在 php.ini中修改,这里用第一种

vim /etc/php.d/protobuf.ini

; Enable protobuf extension module
extension=protobuf.so

如果修改 php.ini,添加如下配置

extension=protobuf.so

确认扩展是否安装成功

php -m | grep -i protobuf

输入 protobuf 则说明安装成功

protobuf

安装protoc

protoc是专门用来生成对应语言的代码文件的工具
可以直接在github的release列表上下载,

wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.0-rc2/protoc-3.11.0-rc-2-linux-x86_64.zip
unzip protoc-3.11.0-rc-2-linux-x86_64.zip
cp -rf ./bin ./include /usr/local

代码测试

命令

protoc -I=./proto/ --php_out=./protobuf ./proto/*

参数解释
-I : 包含的库文件目录
–php_out : 输出php文件
最后一个参数 : 需要编译的proto文件

创建两个目录

mkdir proto
mkdir protbuf

写一个proto文件

vim ./proto/foo.proto

syntax = "proto3";

message Foo 
{
    int32 bar = 1;
    string baz = 2;
    float spam = 3;
}

生成php代码

protoc -I=./proto/ --php_out=./protobuf ./proto/*

执行之后目录下文件如下:

|-- proto
|   `-- foo.proto
`-- protobuf
    |-- Foo.php
    `-- GPBMetadata
        `-- Foo.php

开发时候使用的是

./protobuf/Foo.php

里面有各个字段的get/set方法和序列化反序列化方法

GPMMetadata下的Foo.php文件则是记录,各个字段所在位置的信息

使用 Foo.php
新建一个test.php

setBar(1);
$foo->setBaz('tow');
$foo->setSpam(3.300); 

$packed = $foo->serializeToString();


$parsedFoo = new Foo();
$parsedFoo->mergeFromString($packed);
var_dump($parsedFoo->getBaz());
var_dump($parsedFoo->getBar());
var_dump($parsedFoo->getSpam());

这时还没有引入protobuf库的相关代码,运行的时候回报错一些类没有找到例如:

PHP Fatal error: Class ‘Google\Protobuf\Internal\Message’ not found

运行:

composer require google/protobuf

安装 protobuf库 ,然后再执行 php test.php,输出如下内容说明可以正常使用protobuf了

string(3) "tow"
int(1)
float(3.2999999523163)

thinkPHP中使用protobuf

安装bcmatch
在thinkphp中跑的时候遇到了一个问题

Error: php70w-common conflicts with php-common-5.4.16-46.1.el7_7.x86_64

所以安装了7.0.33版本的bcmatch

yum install php70w-bcmath

查了几个文档,thinkphp引入第三方库的时候,都要几行代码 vender(xx) , 同时pb生成的文件也没有按照thinkphp的文件名称规则上传,不是xxx.class.php,估计自动加载的时候就不行了。想想还是自己写一下自动加载的方法。

在applaction目录下增加三个目录


library   //放protobuf运行时运加载的类文件,vendor里面下载的 src 部分的文件
    |-Google
    |-GPBMetadata
    |-phpdoc.list.xml
protocols //通过protoc 生成的php代码文件
    |-GPBMetadata
    |-Protocols
protofile
    |-common //一些公共文件,foo.proto里面就import了 header.proto文件
        |-header.proto
    |-protos
        |-foo.proto

在protofile目录下执行 生成PB文件命令

protoc -I=./proto/ -I./common/ --php_out=./protobuf ./proto/* ./common/*

在protocols目录下就会生成对应的proto文件

foo.protoc

syntax = "proto3";
import "header.proto";
package protocols;
message Foo
{
    Header head = 1;
    int32 bar = 2;
    string baz = 3;
    float spam = 4;
}

header.protoc

syntax = "proto3";
package protocols;
message Header
{
    uint32 cmd = 1;
    string deviceToken = 2;
    string authCode = 3;
}

修改index.php
增加一个函数


function autoload($path){
    spl_autoload_register(function($className)use($path){
        $className = ltrim($className, '\\');
        $path = rtrim($path, '/');
        if ($lastNsPos = strripos($className, '\\')) {
            $namespace = substr($className, 0, $lastNsPos);
            $className = substr($className, $lastNsPos + 1);
            $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
            $basePath = stristr($namespace, '\\', true);
            if(false === $basePath){
                $basePath = $namespace;
            }

            if(strlen($path) >= strlen($basePath) && (0 === substr_compare($path, $basePath, strlen($basePath)*-1))) {
                $fileName = __DIR__ . DIRECTORY_SEPARATOR . $fileName . $className . '.php';
            }
            else{
                $fileName = $path .DIRECTORY_SEPARATOR. $fileName . $className . '.php';
            }
        }
        else{
            $fileName = $path .DIRECTORY_SEPARATOR. $className  . '.php';
        }

        if (file_exists($fileName)) {
            require $fileName;

            return true;
        }

        return false;
    });
}

在 define(‘APP_DEBUG’) 后添加两行代码

autoload('./library');
autoload('./protocols');

代码测试
在一个controller 中增加一个接口

    public function testPb() {
        $foo = new Foo();
        $foo->setBaz("hahah");
        $foo->setBar(10);
        $foo->setSpam(3.245);
        $header = new Header();
        $header->setAuthCode("fdsfds");
        $header->setCmd(12);
        $foo->setHead($header);

        $str = $foo->serializeToJsonString();
        var_dump($str);

        $parsedFoo = new Foo();
        try {
            $parsedFoo->mergeFromJsonString($str);

        }   catch (\Exception $e) {
            echo "????\n";
        }

        var_dump($parsedFoo->getBar());

        var_dump($parsedFoo->getBaz());

        var_dump($parsedFoo->getSpam());
        var_dump($parsedFoo->getHead()->getAuthCode());

        var_dump($parsedFoo->getHead()->getCmd());
        echo "ok!\n";
    }

用一个工具来测试,我这里用的是postman
发了请求之后输出

string(75) "{"head":{"cmd":12,"authCode":"fdsfds"},"bar":10,"baz":"hahah","spam":3.245}"
int(10)
string(5) "hahah"
float(3.245)
string(6) "fdsfds"
int(12)
ok!

ok说明安装成功

你可能感兴趣的:(linux,php)