protobuf-php/protobuf-plugin
A protoc plugin that generates PHP classes from .proto definitions for the protobuf-php runtime, enabling typed Protocol Buffer message serialization and deserialization in PHP projects.
protobuf-php/protobuf-plugin is a protoc plugin: it does not replace the compiler, it teaches it to emit PHP. Day-to-day, you write .proto files, run protoc, and commit the generated PHP classes alongside the rest of your source.
Minimal setup:
protoc (this package was built in the protobuf 3.x era; pin the compiler, e.g. 3.3–3.5, rather than grabbing the latest).composer require --dev protobuf-php/protobuf-plugin
composer require protobuf-php/protobuf
protoc-gen-php executable. Point protoc at it explicitly so you don't have to fiddle with PATH:vendor/bin/protoc-gen-php --version # sanity check the binary runs
protoc --plugin=protoc-gen-php=vendor/bin/protoc-gen-php \
--php_out=src/Generated \
-I proto \
proto/example.proto
Where to look first:
src/Generated — this is the real documentation for the API your version emits (getters, setters, has*, the base Message class it extends, and how it serializes).tests//fixtures and README usage block, which show the expected protoc invocation and any supported plugin options.composer.json of the runtime package (protobuf-php/protobuf) to confirm the PHP version constraint before you wire this into a modern app.First use case: a single Person message with a string and an int32, compiled and round-tripped through the runtime's serializer in a unit test. If that works, everything else is just more .proto.
Keep a stable layout and a repeatable command. Put schemas in proto/, output in src/Generated/, and map the latter with PSR-4 so the generated classes autoload without extra requires:
{
"autoload": { "psr-4": { "App\\Generated\\": "src/Generated/" } },
"scripts": {
"proto:gen": "protoc --plugin=protoc-gen-php=vendor/bin/protoc-gen-php --php_out=src/Generated -I proto proto/*.proto"
}
}
Then composer proto:gen is the single entry point, and the generated tree becomes a build artifact you can commit.
Commit generated code; pin the toolchain. With a 2017-era plugin, reproducibility matters more than purity. Regenerating on every CI run against a floating protoc will eventually break. Generate locally or in a dedicated job, review the diff, and ship it.
Treat generated classes as DTOs only. Set fields through the generated setters, read through getters/has*, and serialize at the boundary (queue payload, cache blob, socket write). Don't hand-edit generated files; put domain behavior in your own wrappers around the message.
Schema-first evolution. Because the wire format is protobuf, you can add fields without breaking readers. Keep field numbers stable, use reserved for retired ones, and regenerate after each schema change. This is the main payoff over hand-written serializers — make sure your workflow doesn't dilute it.
Integration boundaries. This runtime is not google/protobuf and is not what grpc/grpc uses. If your service is gRPC-based, prefer the official generator; use this package for standalone binary payloads (message queues, caches, internal APIs) where you control both sides.
Testing pattern. Add a small test that round-trips each generated message: build → serialize → parse → assert field equality. It catches both schema mistakes and runtime/plugin version drift early.
protoc version mismatch is the #1 failure. The plugin speaks the CodeGeneratorRequest/Response protocol; newer protoc releases (4.x / editions) may change expectations. If the plugin exits non-zero or emits nothing, drop the compiler version first.package (and any supported namespace option), which may not match your PSR-4 root. Inspect one generated file's namespace line and align composer.json accordingly, or use classmap autoloading for the generated directory.protobuf-php/protobuf base Message. Do not mix them with google/protobuf types; the two are incompatible. Also check the runtime's PHP constraint before adding it to a modern project.google/protobuf/timestamp.proto, Any, Duration may not map to native helpers and can produce generated classes instead. Verify before designing a schema around them, or model those fields as int64/string yourself.protoc runs the plugin as a subprocess and surfaces its stderr. Run the plugin binary directly with --version/no input to isolate whether the failure is the binary (permissions, shebang, PHP path) or the invocation. On Windows use --plugin=protoc-gen-php=vendor\bin\protoc-gen-php.bat.--php_opt=...; check the README/tests for the supported set before inventing flags.protoc is the pragmatic route.protoc/plugin version and regenerate only when schemas change so reviews stay meaningful.How can I help you explore Laravel packages today?