gRPC protoc PHP Client

PHP protoc generated GrpcServiceClient TodoWorld Example

Prerequisites

This requires php >= 5.5, pecl, composer

Install the grpc extension:

$ [sudo] pecl install grpc

Setup for Windows

gRPC PECL Download for Windows

https://windows.php.net/downloads/pecl/releases/grpc/

The PHP extension filename is in the following format:

php_grpc-{GRPC_VERSION}-{PHP_VERSION}-{THREAD_SAFETY}-{VC++_RUNTIME}-{CPU_ARCH}.zip

Select appropriate version for your OS and copy to {PHP_HOME}\ext, then modify your php.ini file to include extension=grpc.

Getting Started

Install x dotnet tool:

$ dotnet tool install --global x 

Add required dependencies to composer.json:

{
  "name": "servicestack/grpc-todoworld",
  "description": "Simple TodoWorld demo of using gRPC from PHP",
  "require": {
    "grpc/grpc": "^v1.3.0",
    "google/protobuf": "^v3.3.0"
  },
  "autoload": {
    "psr-4": {
      "": "route_guide/"
    }
  }
}

Install dependencies:

$ composer install

Add protoc generated TodoWorld DTOs and gRPC GrpcServiceClient:

$ x proto-php https://todoworld.servicestack.net

PHP protoc gRPC insecure Example

Use protoc generated DTOs and GrpcServiceClient to call TodoWorld gRPC Service in main.php:

<?php

require dirname(__FILE__).'/vendor/autoload.php';
@include_once dirname(__FILE__).'/GPBMetadata/Services.php';
@include_once dirname(__FILE__).'/TodoWorld/GrpcServicesClient.php';
@include_once dirname(__FILE__).'/TodoWorld/Hello.php';
@include_once dirname(__FILE__).'/TodoWorld/HelloResponse.php';

$client = new TodoWorld\GrpcServicesClient('todoworld.servicestack.net:5054', [
    'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);

$request = new TodoWorld\Hello();
$request->setName("gRPC PHP");
list($reply, $status) = $client->GetHello($request)->wait();
if ($status->code !== Grpc\STATUS_OK) {
    echo "Call did not complete successfully. Status object:\n";
    var_dump($status);
    exit(1);
}
echo $reply->getResult();

Override main.php with the above PHP Example:

$ x mix todoworld-php

Run example:

$ php main.php

PHP protoc gRPC SSL Example

Download TodoWorld SSL Certificate used for its gRPC HTTP/2 Services:

$ x get https://todoworld.servicestack.net/grpc.crt 

Use certificate when initializing GrpcServicesClient:

<?php

require dirname(__FILE__).'/vendor/autoload.php';
@include_once dirname(__FILE__).'/GPBMetadata/Services.php';
@include_once dirname(__FILE__).'/TodoWorld/GrpcServicesClient.php';
@include_once dirname(__FILE__).'/TodoWorld/Hello.php';
@include_once dirname(__FILE__).'/TodoWorld/HelloResponse.php';

$client = new TodoWorld\GrpcServicesClient('todoworld.servicestack.net:50051', [
    'credentials' => Grpc\ChannelCredentials::createSsl(file_get_contents('grpc.crt')),
]);

$request = new TodoWorld\Hello();
$request->setName("gRPC PHP");
list($reply, $status) = $client->GetHello($request)->wait();
if ($status->code !== Grpc\STATUS_OK) {
    echo "Call did not complete successfully. Status object:\n";
    var_dump($status);
    exit(1);
}
echo $reply->getResult();

Override main.php with the above PHP Example:

$ x mix todoworld-php-ssl

Run example:

$ php main.php

PHP Local Development gRPC SSL CRUD Example

<?php

require dirname(__FILE__).'/vendor/autoload.php';

@include_once dirname(__FILE__).'/GPBMetadata/Services.php';
@include_once dirname(__FILE__).'/TodoWorld/GrpcServicesClient.php';
@include_once dirname(__FILE__).'/TodoWorld/EmptyResponse.php';

@include_once dirname(__FILE__).'/TodoWorld/Hello.php';
@include_once dirname(__FILE__).'/TodoWorld/HelloResponse.php';

@include_once dirname(__FILE__).'/TodoWorld/Todo.php';
@include_once dirname(__FILE__).'/TodoWorld/ResetTodos.php';
@include_once dirname(__FILE__).'/TodoWorld/CreateTodo.php';
@include_once dirname(__FILE__).'/TodoWorld/CreateTodoResponse.php';
@include_once dirname(__FILE__).'/TodoWorld/GetTodo.php';
@include_once dirname(__FILE__).'/TodoWorld/GetTodoResponse.php';
@include_once dirname(__FILE__).'/TodoWorld/GetTodos.php';
@include_once dirname(__FILE__).'/TodoWorld/GetTodosResponse.php';
@include_once dirname(__FILE__).'/TodoWorld/UpdateTodo.php';
@include_once dirname(__FILE__).'/TodoWorld/UpdateTodoResponse.php';
@include_once dirname(__FILE__).'/TodoWorld/DeleteTodo.php';
@include_once dirname(__FILE__).'/TodoWorld/DeleteTodoResponse.php';

$client = new TodoWorld\GrpcServicesClient('localhost:5001', [
    'credentials' => Grpc\ChannelCredentials::createSsl(file_get_contents(dirname(__FILE__).'dev.crt')),
]);

global $client;
function client() { return $GLOBALS['client']; }

function assertStatus($status)
{
    if ($status->code !== Grpc\STATUS_OK) {
        echo "Call did not complete successfully. Status object:\n";
        var_dump($status);
        exit(1);
    }
}

function hello($name) 
{
    $request = new TodoWorld\Hello();
    $request->setName($name);
    list($reply, $status) = client()->GetHello($request)->wait();
    assertStatus($status);
    return $reply->getResult();
}
// echo hello("World") . "\n";

list($reply, $status) = $client->PostResetTodos(new TodoWorld\ResetTodos())->wait();
assertStatus($status);

//POST /todos
$request = new TodoWorld\CreateTodo();
$request->setTitle("ServiceStack");
list($reply, $status) = $client->PostCreateTodo($request)->wait();
assertStatus($status);
$todo = $reply->getResult();
echo "new todo Id: " . $todo->getId() . ", Title: " . $todo->getTitle() . "\n";

//GET /todos
list($reply, $status) = $client->CallGetTodos(new TodoWorld\GetTodos())->wait();
assertStatus($status);
echo "todos: " . count($reply->getResults())  . "\n";

//GET /todos/1
$request = new TodoWorld\GetTodo();
$request->setId($todo->getId());
list($reply, $status) = $client->CallGetTodo($request)->wait();
assertStatus($status);
$todo = $reply->getResult();
echo "get todo Id: " . $todo->getId() . ", Title: " . $todo->getTitle() . "\n";

//PUT /todos/1
$request = new TodoWorld\UpdateTodo();
$request->setId($todo->getId());
$request->setTitle("gRPC");
list($reply, $status) = $client->PutUpdateTodo($request)->wait();
assertStatus($status);

//GET /todos/1
$request = new TodoWorld\GetTodo();
$request->setId($todo->getId());
list($reply, $status) = $client->CallGetTodo($request)->wait();
assertStatus($status);
$todo = $reply->getResult();
echo "get todo Id: " . $todo->getId() . ", Title: " . $todo->getTitle() . "\n";

//DELETE /todos/1
$request = new TodoWorld\DeleteTodo();
$request->setId($todo->getId());
list($reply, $status) = $client->CallDeleteTodo($request)->wait();
assertStatus($status);

//GET /todos
list($reply, $status) = $client->CallGetTodos(new TodoWorld\GetTodos())->wait();
assertStatus($status);
echo "todos: " . count($reply->getResults())  . "\n";

Refer to /clients/php for a complete example project.