rybakit/msgpack
Pure PHP implementation of the MessagePack serialization format, fully compliant with the latest spec. Supports streaming unpacking, unsigned 64-bit integers, custom object types and extensions, with good performance and full test coverage.
Architecture fit. rybakit/msgpack is a pure-PHP, spec-compliant MessagePack codec with a small, explicit API (Packer, BufferUnpacker, static MessagePack facade, streaming append/tryUnpack). In a Laravel monolith, MessagePack is not a default need — Laravel's serialization seams (queue payloads, cache values, sessions, signed URLs) are JSON, PHP serialize, or encrypted-serialize. The package fits where we want a compact, binary-safe, cross-language payload: Redis value encoding, internal event/pub-sub envelopes, blob columns for domain events, ingestion framing for chunked streams, and anywhere we'd otherwise reach for serialize() and regret it. The pure-PHP property is the key architectural selling point: it removes the pecl msgpack extension from the build/deploy matrix (no per-image compilation, no shared-hosting or Fargate friction, identical behavior in CI and local Docker). That's a genuine DevOps win, paid for in CPU.
Integration feasibility. Low at the core, high at the seams. Composer-installable, namespaced, no framework coupling — but no Laravel service provider, facade, cache driver, queue serializer, or Eloquent cast ships with it. All of that is ours to write. A thin adapter is roughly a day of work: a MessagePackServiceProvider binding configured Packer/BufferUnpacker singletons, plus an internal Codec interface so application code never touches the MessagePack\ namespace directly. The expensive integration is Laravel's queue payload path — overriding the serialize()-based job envelope touches every worker, Horizon, failed-job records, and queue:retry. The cache layer is materially easier via a custom store wrapper. Streaming unpacking is well matched to socket or chunked-HTTP ingestion.
Technical risk.
FORCE_STR vs DETECT_STR_BIN, FORCE_ARR/FORCE_MAP vs DETECT_ARR_MAP, and 32- vs 64-bit floats all change the wire representation silently. Type detection also adds measurable overhead on large structures.msgpack extension exposes a different function-level API (msgpack_pack/msgpack_unpack), so a performance escape hatch means rewriting the adapter, not flipping a config flag.Key questions.
json_encode/unserialize and vs pecl-msgpack on our representative payloads (size and CPU)?igbinary or plain serialize?Stack fit. Composer package, PSR-4, standard PHP constraint (verify the exact ^7.x/^8.x range in composer.json), no required extensions for baseline operation, no infrastructure change. This is a library, not a framework integration — treat it as a value codec to be wrapped, never adopted directly in application code.
Migration path. Do not adopt at the framework level first. Sequence:
pack/unpack and payload size against json_encode and serialize on real payloads (job envelopes, cache items, event blobs). Gate everything downstream on those numbers.Codec interface (encode(mixed): string, decode(string): mixed) plus a MessagePackServiceProvider with configured options. All consumers depend on the interface, not the upstream classes.Compatibility. Three axes:
composer audit in CI, record the constraint centrally.v1: + msgpack blob) so older readers reject or route rather than mis-decode.DETECT_STR_BIN on one side and FORCE_STR on the other is a data-corruption bug waiting to happen.Sequencing. Codec abstraction → benchmarks → cache-only rollout → queue rollout behind flags and dual-read → extensions. Keep json_encode on the public HTTP API surface; introducing MessagePack to external clients is a separate, negotiated decision.
Maintenance. The code surface is small, but ownership cost is real:
Support. Community is small (~400 stars, zero recorded dependents), so upstream turnaround is unpredictable and public Q&A coverage is thin. Plan for internal expertise: one or two engineers who can read the MessagePack spec and the library source. Document a fork contingency rather than improvising one during an incident.
Scaling. Pure PHP means encode/decode is CPU-bound in the PHP process. Do not expect it to beat the C extension, and validate it against igbinary on raw throughput. The wins are payload size (Redis memory, wire bytes, log volume) and binary safety — not ops/sec. Watch for:
BufferUnpacker buffers during streaming ingestion; call release() and cap chunk sizes.Failure modes.
InsufficientDataException on truncated reads — the correct pattern is append + tryUnpack, never unpack in a chunk loop.UnpackingFailedException on malformed input — catch and map to a domain error; never leak to a client.int breaks.InvalidOptionException at boot for mutually exclusive option combinations — fail fast in the service provider, not on first request.Ramp-up. The API is small, so developer ramp is hours, not weeks. The semantic subtleties (str/bin, array/map, float width, bigint handling, option interaction) need a one-page internal runbook and one worked example per seam. Realistic effort: roughly one sprint for adapter + provider + contract tests, a second sprint for benchmarking and the first production seam. Time-to-first-production-value: 3–5 weeks for a single team; materially longer if queue payloads are in scope, because of the drain and dual-read requirements.
How can I help you explore Laravel packages today?