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是专门用来生成对应语言的代码文件的工具
可以直接在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)
安装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说明安装成功