Protocol Buffers works great with PHP for building efficient web APIs and microservices. While JSON is common in PHP, Protobuf offers faster serialization and smaller payloads, especially useful for high-traffic applications or mobile API backends.
This guide walks you through everything you need to get started with Protocol Buffers in PHP, from installation to building real working examples. Compare performance with JSON in our detailed comparison.
What You'll Need
- •PHP: Version 7.4 or higher (check with php -v)
- •Composer: PHP package manager (get it here)
- •Protocol Buffer Compiler: We'll install this in the next step
Step 1: Install Protocol Buffers
First, install the PHP protobuf extension using Composer:
composer require google/protobuf
Next, install the Protocol Buffer compiler (protoc). On Ubuntu/Debian:
sudo apt update sudo apt install protobuf-compiler # Verify installation protoc --version
On macOS with Homebrew:
brew install protobuf
On Windows, download from the official releases page and add to your PATH.
Step 2: Set Up Your Project
Create a new PHP project:
mkdir php-protobuf-demo cd php-protobuf-demo composer init --name="your-name/protobuf-demo" composer require google/protobuf mkdir protos mkdir generated
This creates a basic PHP project with folders for your proto files and generated code.
Step 3: Create Your .proto File
Create a file called protos/subscriber.proto. We'll use a telecom subscriber example:
syntax = "proto3";
package telecom;
// Mobile subscriber information
message Subscriber {
  string msisdn = 1;           // Mobile number
  string name = 2;             // Subscriber name
  string email = 3;            // Email address
  SubscriptionType type = 4;   // Plan type
  bool active = 5;             // Account status
  repeated string services = 6; // Active services
}
enum SubscriptionType {
  PREPAID = 0;
  POSTPAID = 1;
  CORPORATE = 2;
}Note: In PHP, we use the package declaration which will become the namespace in generated PHP code.
Step 4: Compile the .proto File
Generate PHP classes from your proto file:
protoc --php_out=generated --proto_path=protos protos/subscriber.proto
This creates PHP files in the generated/ folder. The structure will be:
generated/
  └── Telecom/
      ├── Subscriber.php
      └── SubscriptionType.phpStep 5: Use Protocol Buffers in PHP
Create a file called example.php:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Telecom\Subscriber;
use Telecom\SubscriptionType;
// Create a new subscriber
$subscriber = new Subscriber();
$subscriber->setMsisdn('+91-9876543210');
$subscriber->setName('Telecom Customer');
$subscriber->setEmail('[email protected]');
$subscriber->setType(SubscriptionType::POSTPAID);
$subscriber->setActive(true);
$subscriber->setServices(['Voice', 'Data', '4G LTE']);
echo "Created subscriber: " . $subscriber->getName() . "\n";
echo "MSISDN: " . $subscriber->getMsisdn() . "\n";
echo "Type: " . SubscriptionType::name($subscriber->getType()) . "\n";
// Serialize to binary
$binaryData = $subscriber->serializeToString();
echo "Serialized to " . strlen($binaryData) . " bytes\n\n";
// Deserialize from binary
$newSubscriber = new Subscriber();
$newSubscriber->mergeFromString($binaryData);
echo "Deserialized subscriber: " . $newSubscriber->getName() . "\n";
echo "Email: " . $newSubscriber->getEmail() . "\n";
echo "Active: " . ($newSubscriber->getActive() ? 'Yes' : 'No') . "\n";
// Access repeated fields (services)
echo "\nActive services:\n";
foreach ($newSubscriber->getServices() as $service) {
    echo "  - $service\n";
}Step 6: Run Your Application
Run the PHP script:
php example.php
You should see output like:
Created subscriber: Telecom Customer MSISDN: +91-9876543210 Type: POSTPAID Serialized to 78 bytes Deserialized subscriber: Telecom Customer Email: [email protected] Active: Yes Active services: - Voice - Data - 4G LTE
Saving and Loading from Files
Save and load protobuf data to/from files:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Telecom\Subscriber;
use Telecom\SubscriptionType;
// Create subscriber
$subscriber = new Subscriber();
$subscriber->setMsisdn('+91-9123456789');
$subscriber->setName('Network Admin');
$subscriber->setEmail('[email protected]');
$subscriber->setType(SubscriptionType::CORPORATE);
$subscriber->setActive(true);
// Save to file
file_put_contents('subscriber.bin', $subscriber->serializeToString());
echo "Saved to file\n";
// Load from file
$loadedSubscriber = new Subscriber();
$loadedSubscriber->mergeFromString(file_get_contents('subscriber.bin'));
echo "Loaded: " . $loadedSubscriber->getName() . "\n";
echo "MSISDN: " . $loadedSubscriber->getMsisdn() . "\n";Convert Between JSON and Protobuf
PHP protobuf library supports JSON conversion:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Telecom\Subscriber;
use Telecom\SubscriptionType;
use Google\Protobuf\Internal\Message;
// Create subscriber
$subscriber = new Subscriber();
$subscriber->setMsisdn('+91-9876543210');
$subscriber->setName('Mobile User');
$subscriber->setType(SubscriptionType::PREPAID);
// Convert to JSON
$jsonString = $subscriber->serializeToJsonString();
echo "JSON output:\n";
echo $jsonString . "\n\n";
// Parse from JSON
$jsonData = '{
  "msisdn": "+91-9111111111",
  "name": "New Subscriber",
  "type": "POSTPAID",
  "active": true
}';
$newSubscriber = new Subscriber();
$newSubscriber->mergeFromJsonString($jsonData);
echo "Parsed from JSON: " . $newSubscriber->getName() . "\n";
echo "Type: " . SubscriptionType::name($newSubscriber->getType()) . "\n";Using Protobuf with Laravel
Here's how to use Protobuf in a Laravel API controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Telecom\Subscriber;
use Telecom\SubscriptionType;
class SubscriberController extends Controller
{
    public function create(Request $request)
    {
        // Accept JSON, convert to Protobuf
        $subscriber = new Subscriber();
        $subscriber->setMsisdn($request->input('msisdn'));
        $subscriber->setName($request->input('name'));
        $subscriber->setEmail($request->input('email'));
        $subscriber->setType(SubscriptionType::POSTPAID);
        $subscriber->setActive(true);
        
        // Save to database or process...
        
        // Return protobuf binary
        return response($subscriber->serializeToString())
            ->header('Content-Type', 'application/x-protobuf');
    }
    
    public function get($msisdn)
    {
        // Fetch subscriber from database
        // For demo, create one
        $subscriber = new Subscriber();
        $subscriber->setMsisdn($msisdn);
        $subscriber->setName('Retrieved Subscriber');
        $subscriber->setType(SubscriptionType::PREPAID);
        
        // Return as protobuf
        return response($subscriber->serializeToString())
            ->header('Content-Type', 'application/x-protobuf');
    }
    
    public function parse(Request $request)
    {
        // Receive protobuf binary in request
        $subscriber = new Subscriber();
        $subscriber->mergeFromString($request->getContent());
        
        // Process the subscriber
        return response()->json([
            'name' => $subscriber->getName(),
            'msisdn' => $subscriber->getMsisdn(),
            'type' => SubscriptionType::name($subscriber->getType())
        ]);
    }
}Best Practices for PHP
Use Composer Autoloading
Always use composer autoload instead of manually requiring files. This ensures proper namespace loading.
Handle Binary Data Carefully
When sending protobuf over HTTP, set the correct content type:application/x-protobuf
Keep Generated Code Separate
Store generated PHP files in a separate directory and don't edit them manually. They'll be overwritten on recompilation.
Check Field Existence
Use has methods to check if optional fields are set before accessing them.
Common Issues
Issue: Class not found after compilation
Solution: Make sure your generated files are in a directory that Composer can autoload. Update composer.json to include the generated directory in the autoload section.
Issue: protoc command not found
Solution: Install the Protocol Buffer compiler using your system package manager or download from GitHub releases.
Issue: Namespace errors
Solution: PHP uses the package name from your .proto file as the namespace. Make sure it follows PHP naming conventions.
Related Tools
Additional Resources
Official Documentation & References
- Official PHP Protobuf Tutorial - Google's official PHP guide
- PHP Protobuf on GitHub - Source code and examples
- Protobuf on Packagist - PHP package repository
Conclusion
Protocol Buffers integrates smoothly with PHP, especially for building efficient APIs and microservices. While JSON is more common in the PHP world, Protobuf shines when you need speed, smaller payloads, or are building mobile backends.
Start with the simple examples here, then integrate into your Laravel, Symfony, or custom PHP applications. The performance benefits become clear when handling high traffic or mobile clients with limited bandwidth.