gRPC client for PHP

# gRPC client for PHP

## 概要

恥ずかしながら gRPC というものを知りませんでした。.route ファイルだけを提供されて、「あとはそちらでよろしく」的な投げっぱなしジャーマンを食らったので、やったことをメモしておきます。

## 前提

PHPで gRPC サーバと通信することを目的としています。サーバの構築、Protocol Buffer の定義ファイル（.proto）作成は、すでにできていると仮定します。

## 環境
- Ubuntu 18.04.2 LTS
- PHP 7.2.7

## やること

- gRPC for PHP のインストール
- protoc のインストール
- gRPC PHP Protoc Plugin のインストール
- クライアントPHPコードの生成

実際に行っていることは、以下を参考にしました。
https://grpc.io/docs/quickstart/php/

## gRPC for PHP のインストール

以下を参考にして PHP に拡張モジュールをインストールします。  
https://cloud.google.com/php/grpc?hl=ja

ソースからビルドする方法もありますが、私は pecl でインストールしました。php.ini で extension として追加したら、composer で、プロジェクトに grpc/grpc パッケージを追加します。

```
composer require "grpc/grpc:^v1.1.0"
```

また、通信するためにはランタイムライブラリが必要です。これは、拡張モジュールとしてインストール方法とPHP実装をパッケージとして追加する方法があります。資料にある通り、パフォーマンスを求めるのであれば、拡張モジュールをインストールした方が良いです。が、私はそこまでパフォーマンスを求めていなかったので、composer でのパッケージ追加で対応しました。

```
composer require "google/protobuf:^v3.3.0"
```

## protoc のインストール

protoc は、大雑把にいうと Protocol Buffer 定義ファイル（.proto）から、対応するクラス等を生成するコンパイラです。これを使って、PHPコードを生成するのでインストールします。

https://developers.google.com/protocol-buffers/docs/downloads

上記からリンクをたどるとコンパイル済みのバイナリがあるので最新版をインストールします。私がインストールした時点では、v3.11.4 でした。

```
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip
unzip -d protoc protoc-3.11.4-linux-x86_64.zip 
```

bin と include をパスと通っている場所にコピーします。私の場合は以下。

```
sudo mv protoc/bin/* /usr/local/bin/
sudo mv protoc/include/* /usr/local/include/
```

権限は適宜変更してください。

## gRPC PHP Protoc Plugin のインストール

PHP のクライアント・スタブを生成するには、gRPC PHP Protoc Plugin（grpc_php_plugin） が必要です。apt で protobuf-compiler-grpc を入れれば入ることは入るのですが、古いバージョンであることが多いので、公式の手順にしたがって、インストールします。

```
git clone -b v1.27.2 https://github.com/grpc/grpc
cd grpc
git submodule update --init
make grpc_php_plugin
```

make には時間がかかります。私の場合は30分程かかりました。./bins/opt 以下に grpc_php_plugin ができているはずなので、お好きな場所にどうぞ。私は、パスの通っている以下に置きました。

```
sudo cp -p ./bins/opt/grpc_php_plugin /usr/local/bin/
```

## クライアントPHPコードの生成

最後に protoc を使って、PHPのコードを生成します。.proto ファイルは、提供されている前提ですが、サンプルがないとよくわからんと思うので、公式にあるサンプルを使います。

https://github.com/grpc/grpc/blob/v1.27.2/examples/protos/helloworld.proto

ここでは PHP コードを生成するだけです。gRPCサーバーがなく、実際にリクエストを試したい方は、以下の Node.js チュートリアルを参考にサーバーを作成してください。

https://grpc.io/docs/tutorials/basic/node/  

.proto ファイルがあれば、あとはそれを protoc に渡すだけです。

```
mkdir -p work/protos
mkdir -p work/src
cd work/protos
wget https://raw.githubusercontent.com/grpc/grpc/v1.27.2/examples/protos/helloworld.proto
cd ../
protoc ./protos/helloworld.proto --proto_path=./protos --php_out=./src --grpc_out=./src --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin
tree src 
src/
├  GPBMetadata
│   └ Helloworld.php
└  Helloworld
    ├  GreeterClient.php
    ├── HelloReply.php
    └── HelloRequest.php

2 directories, 4 files
```

これでPHPコードが生成できたと思います。生成されたコードの使用方法は公式を参考にしてください。

https://grpc.io/docs/tutorials/basic/php/  

ちなみに、上記の .proto ファイルで生成すると、勝手に Helloworld の namespace が作成されますが、これは .proto ファイル内のオプション

```
package helloworld;
```

を指定することで namespace が決定されます。それ以外の PHP コード生成に関するオプションには、以下があります。

```
// 生成されるクラスに prefix を付けます
option php_class_prefix = "Sample";

// 生成されるクラスの namespace を変更します。デフォルトは package を元に決定されます。
option php_namespace = "App\\Services\\Sample";

// 生成されるメタデータクラスの namespace を変更します。
option php_metadata_namespace = "App\\Services\\Sample\\GPBMetadata";
```

その他のオプションは以下から探してみてください。  
https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto