Goでクライアントを作るときには、brew
やgo get
でパッケージをいくつか入れるだけで済むのですが、PHPの方ではいくつかハマりどころがあったのでまとめました。
前提
- protoコマンドがインストールされている
- 使用するRPC方式はUnaryRPCである
- コード生成はローカル環境で行う
扱うprotoファイル
下記のprotoに少し変更をかけたものを扱います。
https://grpc.io/docs/languages/php/quickstart/
package hello;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
コード生成
下記ページを参考にしました。
https://grpc.io/docs/languages/php/quickstart/
コード生成用のPHPプラグインを追加
protoファイルからPHP用の各種クラスを生成するために、grpc_php_plugin を入れる必要があります。
$ git clone -b v1.30.0 https://github.com/grpc/grpc
$ cd grpc && git submodule update --init && make grpc_php_plugin
すると、ソースを展開したディレクトリに bins/opt/grpc_php_plugin
が生成されます。
コード生成実行
下記コマンドを入力します。
$ protoc --proto_path=proto \
--php_out=src/gen \
--grpc_out=src/gen \
--plugin=protoc-gen-grpc=./grpc/bins/opt/grpc_php_plugin \
./proto/hello.proto
この時のオプションとして、
-
--proto_path
にはprotoファイルが配置されているディレクトリを指定する -
--php_out
と--grpc_out
は同じディレクトリを指定する -
--plugin=protoc-gen-grpc=
に、先ほどプラグインをインストールしたディレクトリのbins/opt/grpc_php_plugin
を指定する
を行います。
これでコード生成はOKです。
クライアント環境準備
インストールするパッケージは下記ページを参考にしました。
https://cloud.google.com/php/grpc?hl=ja#php-implementation
Dockerの上で動かしたPHPで、gRPCのリクエストを送るための環境を構築します。
php.ini
grpc.so
拡張パッケージの記述がポイントです。
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
extension = grpc.so
Dockerfile
peclでgrpcパッケージを入れることがポイントです。
FROM php:7.2-stretch
RUN apt-get update -y \
&& apt-get install -y zip autoconf zlib1g-dev \
&& apt-get clean
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
COPY php.ini /usr/local/etc/php/php.ini
RUN pecl install grpc
WORKDIR /var/local
COPY . .
RUN composer install
composer.json
ここでは先ほどのコード生成によってファイルが格納された先を src/gen
として扱っています。
{
"autoload": {
"psr-4": {
"Hello\\": "src/gen/Hello",
"GPBMetadata\\": "src/gen/GPBMetadata"
}
},
"require": {
"php": ">=7.2",
"google/protobuf": ">=3.0",
"grpc/grpc": ">=v1.27.0"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/stanley-cheung/Protobuf-PHP"
}
]
}
ポイントは、
-
google/protobuf
パッケージのインストール -
grpc/grpc
パッケージのインストール - コード生成されたクラスをautoloadで読み込み指定する
ことです。
docker-compose.yaml
先ほどのphp.iniを、ボリュームマウントでコンテナに配置することがポイントです。
version: "3"
services:
php:
build: .
volumes:
- ./php.ini:/usr/local/etc/php/php.ini
- .:/var/local/
ports:
- 80:80
クライアント実装
実装例です。
<?php
use Hello\GreeterClient;
use Hello\HelloRequest;
$hostname = 'localhost:8000';
$client = GreeterClient($hostname, [
'credentials' => \Grpc\ChannelCredentials::createInsecure()
]);
$request = new HelloRequest();
$request->setName("DummyName");
list($reply, $status) = $client->SayHello($request)->wait();
$message = $reply->getMessage();
この時vendor配下に \Grpc\ChannelCredentials
クラスが存在せず、エディタでは警告等が出ます。
これはcomposerで入れるものではなく、Dockerfileとphp.iniで指定したgrpc拡張パッケージに含まれています。
よって、必要なライブラリ自体はDocker側にインストールされているため、実行時には正常に通ります。
(個人的にはここがハマりポイントでした)
実行
オートローダーを読み込んで、クライアント実装のスクリプトを読み込めば実行されます。
$ docker-compose run --rm php -a
php> require_once('vendor/autoload.php');
php> require_once('scripts/RunHello.php');
あとはこのクライアントをクラスに閉じ込めたり、composerのパッケージ化などを行えばWebサーバー等にも組み込むことができます。