PHPでgRPC叩く手始め
なんかもうアレなので、PHPでgRPCのサーバーを叩いてみる。まずは環境整備から
- 流れ的にはprotobufを定義して、それを元にPHPからgRPCと通信するclientを作ってそれを使ってgPRCを叩く模様
Environment
- 公式のままやってみる
grpc
# peclが必要 yum install --enablerepo=remi-php71 php-pear gcc-c++ make zlib-devel php-devel pecl install grpc echo 'extension=grpc.so' >> /etc/php.ini
参考: https://github.com/grpc/grpc/issues/11957 https://github.com/grpc/grpc/issues/11057
protobuff
pecl install protobuf echo 'extension=protobuf.so' >> /etc/php.ini # 現時点の最新版protobuf-3.5.0.1は下記のエラーが出るのでv3.4を使う。。。 PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/protobuf.so' - /usr/lib64/php/modules/protobuf.so: undefined symbol: timelib_update_ts in Unknown on line 0 See : https://github.com/google/protobuf/issues/3929 # 一旦protobuf-3.4.0 install pecl uninstall protobuf pecl install protobuf-3.4.0 # protobufのコンパイラは下記から https://github.com/google/protobuf/releases/
grpc用のprotobuf plugin
#repo clone git clone --recursive -b v1.7.x https://github.com/grpc/grpc # 公式には書いてないけどこれやらないと下のmakeができないっぽい cd grpc/third_party/protobuf ./autogen.sh cd grpc make grpc_php_plugin ※上手くいかない時は下記が足りていないかも libtool shtool autoconf autogen
サンプルproto
syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.helloworld"; option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloAgain (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
- phpのコード生成
protoc --proto_path=examples/protos --php_out=examples/php --grpc_out=examples/php --plugin=protoc-gen-grpc=bins/opt/grpc_php_plugin ./examples/protos/helloworld.proto
- sampleを実行してみる
require dirname(__FILE__).'/vendor/autoload.php'; @include_once dirname(__FILE__).'/Helloworld/GreeterClient.php'; @include_once dirname(__FILE__).'/Helloworld/HelloReply.php'; @include_once dirname(__FILE__).'/Helloworld/HelloRequest.php'; @include_once dirname(__FILE__).'/GPBMetadata/Helloworld.php'; function greet($name) { $client = new Helloworld\GreeterClient('localhost:50051', [ 'credentials' => Grpc\ChannelCredentials::createInsecure(), ]); $request = new Helloworld\HelloRequest(); $request->setName($name); list($reply, $status) = $client->SayHello($request)->wait(); var_dump($reply); var_dump($status); return $message; } $name = !empty($argv[1]) ? $argv[1] : 'world'; echo greet($name)."\n"; [root@6b0b0fc608dc php]# php greeter_client.php wow /var/workspace/grpc/examples/php/greeter_client.php:42: NULL /var/workspace/grpc/examples/php/greeter_client.php:43: class stdClass#12 (3) { public $metadata => array(0) { } public $code => int(14) public $details => string(14) "Connect Failed" } PHP Fatal error: Uncaught Error: Call to a member function getMessage() on null in /var/workspace/grpc/examples/php/greeter_client.php:44 Stack trace: #0 /var/workspace/grpc/examples/php/greeter_client.php(53): greet('wow') #1 {main} thrown in /var/workspace/grpc/examples/php/greeter_client.php on line 44
それっぽく動いてる? ※grpc serverはnodeで動くので立ち上げていない
次は実際にgRPCサーバーを立てて動作確認