09 June 2020
How to connect with gRPC service in PHP application? gRPC PHP tutorial

More and more developers and companies are discovering the benefits of microservices. And while PHP is usually not the first choice for this architecture, it is now more than viable to create efficient web apps based on microservices with PHP. To that end, Google’s gRPC and Protobuf solutions are a big help. Today, I’m going to show you how to use gRPC with PHP.
But before we get to the gRPC PHP issue, let’s talk a little about how the gRPC framework can help ease some typical microservices pains in the first place.
Microservices and gRPC – introduction
As the need for scalability and reliability grows, the microservices architecture becomes more and more popular. The main advantage of microservices is the possibility of adding more resources in places where they are actually needed as well as fault isolation, simplicity of the modules and possibility to use different technologies across the platform.
As great as it sounds, microservices-based applications struggle with some challenges of their own. Difficulties with global testing, hard debugging, deployment problems, the complexity of communication between services and versioning are usually listed as the major drawbacks of the microservices concept.
This is where Google steps in with its gRPC and Protobuf solutions.
The gRPC is a universal framework based on the remote procedure call (RPC) protocol. The main idea of RPC is to create a service whose methods can be called remotely as if they were the client methods. The framework provides bidirectional streaming with integrated authentication and HTTP2-based transport.
Benefits of gRPC
To serialize the structured data, gRPC uses protocol buffers. With protocol buffers, you can define the structure of the data in a .proto file and then use a generator to produce the source code in a variety of programming languages.
Which leads to the first advantage of the protocol buffers – an easy and fast way to establish the communication base for the services.
Another benefit of using the buffers is backward compatibility. You can update the data structure with no impact on the parts of the system deployed with the previous format.
Also, the protocol buffers are simple, small and fast. You can read detailed information about gRPC and protocol buffers at the framework’s official website as well as in Google’s resources for developers.
gRPC for PHP
gRPC works across languages and platforms. Does it mean that it can be used with PHP? PHP is not considered the best solution for microservices mainly because of its memory issues, speed, single-threading and short-lived streaming. Still, developing microservices with PHP is possible, and with the right tools, it can be quite effective.
There are solutions such as Mezzio (formerly Expressive) and Swoft frameworks supporting asynchronous programming through Swoole. The gRPC has no direct support for building a PHP-based server. This can be done with third-party tools such as the spiral/php-grpc server. What about the client’s side, is it supported? The answer is yes.
As gRPC’s popularity grows, you may find yourself in need of integrating it with some services based on it even when your application does not use the microservices architecture. For example, you may want to use some cloud services such as Google APIs.
Also, as I mentioned, microservices development encourages using different technologies for the modules. This can become handy if you want to migrate gradually from a monolith PHP application to microservices using different languages such as Node.js, Golang or Python.
Adding gRPC to PHP application
Here are steps you need to take to introduce gRPC communication in your PHP application.
1. Make sure you have gRPC and the PHP gRPC extension up and running.
You can do that by running php -m | head in command line. If the extension is not listed, you will need to install it. The instructions on how to do that can be found here.
If you want to use Docker and your base PHP image does not have the extension, you will need to add something like this to your Dockerfile:
RUN pecl install grpc && \
docker-php-ext-enable grpc
2. Add Google Protobuf, gRPC and the gRPC extension to your project using Composer:
composer req google/protobuf
composer req grpc/grpc
composer req ext-grpc
3. Get the protobuf compiler protoc or use a docker image for file generation.
You can get protoc by following this guide.
Instead of installing protoc locally, you can use the docker image that will help with the file generation.
4. Add the .proto files to your application and generate your PHP files.
The first step here would be getting the protofile/protofiles and placing them in the application. For demonstration purposes, I have downloaded the Google Example Bookstore API protofile and used it in a simple library application in Symfony. The bookstore.proto file is used in Google gRPC tutorials and it is available here.
It is also pasted below. In the top part of the file, you will find information about the syntax version, imports and bookstore service definition. Further on you will see the resources, requests and responses definitions.
// Copyright 2016 Google Inc. All Rights Reserved. | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// | |
//////////////////////////////////////////////////////////////////////////////// | |
syntax = "proto3"; | |
package endpoints.examples.bookstore; | |
option java_multiple_files = true; | |
option java_outer_classname = "BookstoreProto"; | |
option java_package = "com.google.endpoints.examples.bookstore"; | |
import "google/protobuf/empty.proto"; | |
// A simple Bookstore API. | |
// | |
// The API manages shelves and books resources. Shelves contain books. | |
service Bookstore { | |
// Returns a list of all shelves in the bookstore. | |
rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {} | |
// Creates a new shelf in the bookstore. | |
rpc CreateShelf(CreateShelfRequest) returns (Shelf) {} | |
// Returns a specific bookstore shelf. | |
rpc GetShelf(GetShelfRequest) returns (Shelf) {} | |
// Deletes a shelf, including all books that are stored on the shelf. | |
rpc DeleteShelf(DeleteShelfRequest) returns (google.protobuf.Empty) {} | |
// Returns a list of books on a shelf. | |
rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {} | |
// Creates a new book. | |
rpc CreateBook(CreateBookRequest) returns (Book) {} | |
// Returns a specific book. | |
rpc GetBook(GetBookRequest) returns (Book) {} | |
// Deletes a book from a shelf. | |
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {} | |
} | |
// A shelf resource. | |
message Shelf { | |
// A unique shelf id. | |
int64 id = 1; | |
// A theme of the shelf (fiction, poetry, etc). | |
string theme = 2; | |
} | |
// A book resource. | |
message Book { | |
// A unique book id. | |
int64 id = 1; | |
// An author of the book. | |
string author = 2; | |
// A book title. | |
string title = 3; | |
} | |
// Response to ListShelves call. | |
message ListShelvesResponse { | |
// Shelves in the bookstore. | |
repeated Shelf shelves = 1; | |
} | |
// Request message for CreateShelf method. | |
message CreateShelfRequest { | |
// The shelf resource to create. | |
Shelf shelf = 1; | |
} | |
// Request message for GetShelf method. | |
message GetShelfRequest { | |
// The ID of the shelf resource to retrieve. | |
int64 shelf = 1; | |
} | |
// Request message for DeleteShelf method. | |
message DeleteShelfRequest { | |
// The ID of the shelf to delete. | |
int64 shelf = 1; | |
} | |
// Request message for ListBooks method. | |
message ListBooksRequest { | |
// ID of the shelf which books to list. | |
int64 shelf = 1; | |
} | |
// Response message to ListBooks method. | |
message ListBooksResponse { | |
// The books on the shelf. | |
repeated Book books = 1; | |
} | |
// Request message for CreateBook method. | |
message CreateBookRequest { | |
// The ID of the shelf on which to create a book. | |
int64 shelf = 1; | |
// A book resource to create on the shelf. | |
Book book = 2; | |
} | |
// Request message for GetBook method. | |
message GetBookRequest { | |
// The ID of the shelf from which to retrieve a book. | |
int64 shelf = 1; | |
// The ID of the book to retrieve. | |
int64 book = 2; | |
} | |
// Request message for DeleteBook method. | |
message DeleteBookRequest { | |
// The ID of the shelf from which to delete a book. | |
int64 shelf = 1; | |
// The ID of the book to delete. | |
int64 book = 2; | |
} |
Next step is to take care of the source code generation, which was processed via namely/docker-protoc with the following command:
docker run -v `pwd`:/defs namely/protoc-all -f library.proto -l php -o library/
The command should be run from the .proto file directory. The -o switch is optional and allows for specifying the source code location. The -f switch points in the file can be replaced with -d to process all protofiles in the location.
The place of protorepo generation can be modified with -i switch. More details can be found in the namely/docker-protoc documentation linked in point 3.
Let’s take a look at the generated classes and their structure. I have placed my proto file and the generated code out of the src directory but it can be placed anywhere. The generated tree looks as follows:
The generated client code is shown below. It is worth it to note that the comment at the very top of the generated code should not be modified.
// GENERATED CODE -- DO NOT EDIT! | |
// Original file comments: | |
// Copyright 2016 Google Inc. All Rights Reserved. | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// | |
// ////////////////////////////////////////////////////////////////////////////// | |
// | |
namespace Endpoints\Examples\Bookstore; | |
/** | |
* A simple Bookstore API. | |
* | |
* The API manages shelves and books resources. Shelves contain books. | |
*/ | |
class BookstoreClient extends \Grpc\BaseStub { | |
/** | |
* @param string $hostname hostname | |
* @param array $opts channel options | |
* @param \Grpc\Channel $channel (optional) re-use channel object | |
*/ | |
public function __construct($hostname, $opts, $channel = null) { | |
parent::__construct($hostname, $opts, $channel); | |
} | |
/** | |
* Returns a list of all shelves in the bookstore. | |
* @param \Google\Protobuf\GPBEmpty $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function ListShelves(\Google\Protobuf\GPBEmpty $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/ListShelves', | |
$argument, | |
['\Endpoints\Examples\Bookstore\ListShelvesResponse', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Creates a new shelf in the bookstore. | |
* @param \Endpoints\Examples\Bookstore\CreateShelfRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function CreateShelf(\Endpoints\Examples\Bookstore\CreateShelfRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/CreateShelf', | |
$argument, | |
['\Endpoints\Examples\Bookstore\Shelf', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Returns a specific bookstore shelf. | |
* @param \Endpoints\Examples\Bookstore\GetShelfRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function GetShelf(\Endpoints\Examples\Bookstore\GetShelfRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/GetShelf', | |
$argument, | |
['\Endpoints\Examples\Bookstore\Shelf', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Deletes a shelf, including all books that are stored on the shelf. | |
* @param \Endpoints\Examples\Bookstore\DeleteShelfRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function DeleteShelf(\Endpoints\Examples\Bookstore\DeleteShelfRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/DeleteShelf', | |
$argument, | |
['\Google\Protobuf\GPBEmpty', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Returns a list of books on a shelf. | |
* @param \Endpoints\Examples\Bookstore\ListBooksRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function ListBooks(\Endpoints\Examples\Bookstore\ListBooksRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/ListBooks', | |
$argument, | |
['\Endpoints\Examples\Bookstore\ListBooksResponse', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Creates a new book. | |
* @param \Endpoints\Examples\Bookstore\CreateBookRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function CreateBook(\Endpoints\Examples\Bookstore\CreateBookRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/CreateBook', | |
$argument, | |
['\Endpoints\Examples\Bookstore\Book', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Returns a specific book. | |
* @param \Endpoints\Examples\Bookstore\GetBookRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function GetBook(\Endpoints\Examples\Bookstore\GetBookRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/GetBook', | |
$argument, | |
['\Endpoints\Examples\Bookstore\Book', 'decode'], | |
$metadata, $options); | |
} | |
/** | |
* Deletes a book from a shelf. | |
* @param \Endpoints\Examples\Bookstore\DeleteBookRequest $argument input argument | |
* @param array $metadata metadata | |
* @param array $options call options | |
*/ | |
public function DeleteBook(\Endpoints\Examples\Bookstore\DeleteBookRequest $argument, | |
$metadata = [], $options = []) { | |
return $this->_simpleRequest('/endpoints.examples.bookstore.Bookstore/DeleteBook', | |
$argument, | |
['\Google\Protobuf\GPBEmpty', 'decode'], | |
$metadata, $options); | |
} | |
} |
Besides the client, we also see resource classes which are models of the actual data. You can see the Book.php resource class below.
<?php | |
# Generated by the protocol buffer compiler. DO NOT EDIT! | |
# source: bookstore.proto | |
namespace Endpoints\Examples\Bookstore; | |
use Google\Protobuf\Internal\GPBType; | |
use Google\Protobuf\Internal\RepeatedField; | |
use Google\Protobuf\Internal\GPBUtil; | |
/** | |
* A book resource. | |
* | |
* Generated from protobuf message <code>endpoints.examples.bookstore.Book</code> | |
*/ | |
class Book extends \Google\Protobuf\Internal\Message | |
{ | |
/** | |
* A unique book id. | |
* | |
* Generated from protobuf field <code>int64 id = 1;</code> | |
*/ | |
protected $id = 0; | |
/** | |
* An author of the book. | |
* | |
* Generated from protobuf field <code>string author = 2;</code> | |
*/ | |
protected $author = ''; | |
/** | |
* A book title. | |
* | |
* Generated from protobuf field <code>string title = 3;</code> | |
*/ | |
protected $title = ''; | |
/** | |
* Constructor. | |
* | |
* @param array $data { | |
* Optional. Data for populating the Message object. | |
* | |
* @type int|string $id | |
* A unique book id. | |
* @type string $author | |
* An author of the book. | |
* @type string $title | |
* A book title. | |
* } | |
*/ | |
public function __construct($data = NULL) { | |
\GPBMetadata\Bookstore::initOnce(); | |
parent::__construct($data); | |
} | |
/** | |
* A unique book id. | |
* | |
* Generated from protobuf field <code>int64 id = 1;</code> | |
* @return int|string | |
*/ | |
public function getId() | |
{ | |
return $this->id; | |
} | |
/** | |
* A unique book id. | |
* | |
* Generated from protobuf field <code>int64 id = 1;</code> | |
* @param int|string $var | |
* @return $this | |
*/ | |
public function setId($var) | |
{ | |
GPBUtil::checkInt64($var); | |
$this->id = $var; | |
return $this; | |
} | |
/** | |
* An author of the book. | |
* | |
* Generated from protobuf field <code>string author = 2;</code> | |
* @return string | |
*/ | |
public function getAuthor() | |
{ | |
return $this->author; | |
} | |
/** | |
* An author of the book. | |
* | |
* Generated from protobuf field <code>string author = 2;</code> | |
* @param string $var | |
* @return $this | |
*/ | |
public function setAuthor($var) | |
{ | |
GPBUtil::checkString($var, True); | |
$this->author = $var; | |
return $this; | |
} | |
/** | |
* A book title. | |
* | |
* Generated from protobuf field <code>string title = 3;</code> | |
* @return string | |
*/ | |
public function getTitle() | |
{ | |
return $this->title; | |
} | |
/** | |
* A book title. | |
* | |
* Generated from protobuf field <code>string title = 3;</code> | |
* @param string $var | |
* @return $this | |
*/ | |
public function setTitle($var) | |
{ | |
GPBUtil::checkString($var, True); | |
$this->title = $var; | |
return $this; | |
} | |
} |
The structure of gRPC requests is also defined in the proto file and gives us the generated classes. For instance the GetBookRequest.php:
<?php | |
# Generated by the protocol buffer compiler. DO NOT EDIT! | |
# source: bookstore.proto | |
namespace Endpoints\Examples\Bookstore; | |
use Google\Protobuf\Internal\GPBType; | |
use Google\Protobuf\Internal\RepeatedField; | |
use Google\Protobuf\Internal\GPBUtil; | |
/** | |
* Request message for GetBook method. | |
* | |
* Generated from protobuf message <code>endpoints.examples.bookstore.GetBookRequest</code> | |
*/ | |
class GetBookRequest extends \Google\Protobuf\Internal\Message | |
{ | |
/** | |
* The ID of the shelf from which to retrieve a book. | |
* | |
* Generated from protobuf field <code>int64 shelf = 1;</code> | |
*/ | |
protected $shelf = 0; | |
/** | |
* The ID of the book to retrieve. | |
* | |
* Generated from protobuf field <code>int64 book = 2;</code> | |
*/ | |
protected $book = 0; | |
/** | |
* Constructor. | |
* | |
* @param array $data { | |
* Optional. Data for populating the Message object. | |
* | |
* @type int|string $shelf | |
* The ID of the shelf from which to retrieve a book. | |
* @type int|string $book | |
* The ID of the book to retrieve. | |
* } | |
*/ | |
public function __construct($data = NULL) { | |
\GPBMetadata\Bookstore::initOnce(); | |
parent::__construct($data); | |
} | |
/** | |
* The ID of the shelf from which to retrieve a book. | |
* | |
* Generated from protobuf field <code>int64 shelf = 1;</code> | |
* @return int|string | |
*/ | |
public function getShelf() | |
{ | |
return $this->shelf; | |
} | |
/** | |
* The ID of the shelf from which to retrieve a book. | |
* | |
* Generated from protobuf field <code>int64 shelf = 1;</code> | |
* @param int|string $var | |
* @return $this | |
*/ | |
public function setShelf($var) | |
{ | |
GPBUtil::checkInt64($var); | |
$this->shelf = $var; | |
return $this; | |
} | |
/** | |
* The ID of the book to retrieve. | |
* | |
* Generated from protobuf field <code>int64 book = 2;</code> | |
* @return int|string | |
*/ | |
public function getBook() | |
{ | |
return $this->book; | |
} | |
/** | |
* The ID of the book to retrieve. | |
* | |
* Generated from protobuf field <code>int64 book = 2;</code> | |
* @param int|string $var | |
* @return $this | |
*/ | |
public function setBook($var) | |
{ | |
GPBUtil::checkInt64($var); | |
$this->book = $var; | |
return $this; | |
} | |
} |
After sending the gRPC request, we will get the response containing either the resource or the response class. The response classes represent the set of data, for example, the list of resources. Let’s check out the ListBooksResponse.php.
<?php | |
# Generated by the protocol buffer compiler. DO NOT EDIT! | |
# source: bookstore.proto | |
namespace Endpoints\Examples\Bookstore; | |
use Google\Protobuf\Internal\GPBType; | |
use Google\Protobuf\Internal\RepeatedField; | |
use Google\Protobuf\Internal\GPBUtil; | |
/** | |
* Response message to ListBooks method. | |
* | |
* Generated from protobuf message <code>endpoints.examples.bookstore.ListBooksResponse</code> | |
*/ | |
class ListBooksResponse extends \Google\Protobuf\Internal\Message | |
{ | |
/** | |
* The books on the shelf. | |
* | |
* Generated from protobuf field <code>repeated .endpoints.examples.bookstore.Book books = 1;</code> | |
*/ | |
private $books; | |
/** | |
* Constructor. | |
* | |
* @param array $data { | |
* Optional. Data for populating the Message object. | |
* | |
* @type \Endpoints\Examples\Bookstore\Book[]|\Google\Protobuf\Internal\RepeatedField $books | |
* The books on the shelf. | |
* } | |
*/ | |
public function __construct($data = NULL) { | |
\GPBMetadata\Bookstore::initOnce(); | |
parent::__construct($data); | |
} | |
/** | |
* The books on the shelf. | |
* | |
* Generated from protobuf field <code>repeated .endpoints.examples.bookstore.Book books = 1;</code> | |
* @return \Google\Protobuf\Internal\RepeatedField | |
*/ | |
public function getBooks() | |
{ | |
return $this->books; | |
} | |
/** | |
* The books on the shelf. | |
* | |
* Generated from protobuf field <code>repeated .endpoints.examples.bookstore.Book books = 1;</code> | |
* @param \Endpoints\Examples\Bookstore\Book[]|\Google\Protobuf\Internal\RepeatedField $var | |
* @return $this | |
*/ | |
public function setBooks($var) | |
{ | |
$arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Endpoints\Examples\Bookstore\Book::class); | |
$this->books = $arr; | |
return $this; | |
} | |
} |
The response should also contain information about the request status. You can find detailed information about gRPC statuses and error handling here.
5. Use the generated code in the application.
Once we have the generated code, we can easily wrap it in the custom class which will allow the communication with gRPC service as if it was part of the system. Below you can see an example implementation of the method and gRPC error handling.
<?php declare(strict_types=1); | |
namespace App\Proto; | |
use App\Exception\GrpcException; | |
use Endpoints\Examples\Bookstore\BookstoreClient; | |
use Endpoints\Examples\Bookstore\CreateShelfRequest; | |
use Endpoints\Examples\Bookstore\GetBookRequest; | |
use Endpoints\Examples\Bookstore\GetShelfRequest; | |
use Endpoints\Examples\Bookstore\Shelf; | |
use Grpc\ChannelCredentials; | |
class LibraryBookstoreClient | |
{ | |
/** @var BookstoreClient */ | |
private $client; | |
/** @var BookModelFactory */ | |
private $bookModelFactory; | |
public function __construct(string $host, BookModelFactory $bookModelFactory) | |
{ | |
$this->client = new BookstoreClient($host, ['credentials' => ChannelCredentials::createDefault()]); | |
$this->bookModelFactory = $bookModelFactory; | |
} | |
/** | |
* @throws GrpcException | |
*/ | |
public function getBook(string $shelfId, string $bookId): BookModel | |
{ | |
$getBookRequest = new GetBookRequest(); | |
$getBookRequest->setShelf($shelfId); | |
$getBookRequest->setBook($bookId); | |
$request = $this->client->GetBook($getBookRequest); | |
$response = $request->wait(); | |
$this->handleErrorResponse($response); | |
return $this->bookModelFactory->create($response[0]); | |
} | |
private function handleErrorResponse(array $response): void | |
{ | |
if ($response[1]->code !== GrpcCodeType::GRPC_STATUS_OK) { | |
throw new GrpcException( | |
sprintf( | |
'gRPC request failed : error code: %s, details: %s', | |
$response[1]->code, | |
$response[1]->details | |
) | |
); | |
} | |
} | |
} |
gRPC PHP summary
The connection with gRPC service may seem complicated, especially if you are used to REST and have never used remote procedure calls before. But thanks to Protobuf and protoc generator, it is actually quite simple.
Using generated files in a PHP application, you can easily establish communication with the microservices written in any language. Choosing the gRPC as a communication protocol while migrating the system from a monolith architecture to microservices may be a huge advantage.
Contract programming supported by protocol buffers helps set up a communication base for the services and maintain backward compatibility. The simplicity and speed of protocol buffers make for an efficient system.
Using gRPC and protocol buffers, we can take advantage of the microservices and build simple, isolated modules with PHP, other technologies or both.
The gRPC also provides a convenient way of utilizing the cloud services or any third party service we may want to use.
When used that way, the gRPC PHP combination can become really powerful! Contact us to implement gRPC into your PHP project and book a free one-hour consultation. 🚀