symfony/json-streamer
Symfony JsonStreamer provides powerful methods to read and write data structures from and into JSON streams, enabling memory-efficient processing of large JSON documents without loading everything at once.
json_encode()/json_decode() for payloads >10MB, mitigating PHP’s default memory limits.StreamedResponse, Queue Workers, and Artisan CLI tools for incremental processing.Serializer component (already used in Laravel for form/data transformation), reducing duplication.v8.1.0-BETA3 baseline used in the prior assessment to a stable 8.1.x patch line (v8.1.9) — nine patch releases, no breaking changes, no deprecations.#66744, Keep streamable resources for compiler passes that run after StreamablePass) confirms the package now participates in Symfony’s DI container compilation, not just runtime serialization. That is the correct architecture for Laravel (compiled container, config:cache, Octane preloading), but it moves part of the risk surface from “runtime serialization” into “container build / deployment”.StreamedResponse for chunked JSON APIs (paginated exports).Serializer binding to support JsonStreamer for complex object graphs.json_decode() in jobs with incremental parsing (1GB JSON files).Artisan commands for data migration (php artisan import:json).php artisan optimize, config:cache, and Octane’s container preload.symfony/serializer (v6.0+ for Laravel 10+; v5.4+ for Laravel 9) and symfony/property-access (bundled in Laravel 10+).8.1.0-BETA3 → ^8.1.9 is a drop-in constraint bump; no API changes, no config changes, no migration scripts.php artisan optimize:clear then optimize) so the corrected compiler pass ordering takes effect.StreamablePass. This is the correct fix, but it means resources can outlive the pass that created them during container compilation.composer install/artisan optimize in CI — a regression here indicates a resource not being released between passes.php artisan optimize:clear && php artisan optimize cycle on a clean checkout, plus an Octane boot/octane:reload cycle.finally blocks under Octane and queue workers; monitor open file descriptors (lsof -p <pid>) during soak tests.missing generator fixes hold.hasMany/belongsTo with include_null_properties and union types.JsonStreamer to Laravel Broadcast channels.StreamablePass run predictably inside Laravel’s container compilation order (which differs from a vanilla Symfony Kernel), and does the v8.1.9 retention behaviour hold when third-party packages register passes after it?php artisan optimize output/compile time before and after.JsonStreamer compare to json_encode()/ijson for 100MB–1GB payloads on the 8.1.x stable line (previously benchmarked against BETA3)?^8.1.9 to confirm BETA-era numbers still hold.JsonStreamer correctly handle Eloquent accessors/mutators, casts, and hidden attributes?User model and nested Post relationships.JsonStreamer manage malformed JSON or partial streams (network interruptions)?StreamedResponse failures.JsonStreamer integrate with Laravel Broadcast for incremental WebSocket pushes?StreamedResponse for chunked JSON APIs (/exports/large-report):
use Symfony\Component\Serializer\JsonStreamer;
use Illuminate\Http\StreamedResponse;
return new StreamedResponse(
fn() => (new JsonStreamer())->write($data, $response->getEmitter()),
200,
['Content-Type' => 'application/json']
);
Serializer binding:
$serializer = app(\Symfony\Component\Serializer\Serializer::class);
$streamer = new JsonStreamer($serializer);
$streamer->write($eloquentCollection, $response->getEmitter());
json_decode() with incremental parsing:
$streamer->read($filePath, function ($chunk) {
// Process chunk (e.g., save to DB)
});
$streamer = new JsonStreamer();
$streamer->read($file, function ($data) {
DB::table('reports')->insert($data);
});
artisan optimize and Octane preload. Treat container compilation as an integration surface, not just a black box."require": {
"symfony/serializer": "^6.0",
"symfony/json-streamer": "^8.1.9"
}
Pin ^8.1.9 (or later 8.1.x) rather than any BETA constraint.Phase 0: Constraint & Cache Reset (new, ~30 min)
symfony/json-streamer from the 8.1.0-BETA3 constraint to ^8.1.9.composer update symfony/json-streamer and inspect for no unexpected transitive bumps.php artisan optimize:clear, then php artisan optimize. Confirm the container compiles cleanly and note build time/memory as a baseline.php artisan octane:reload and verify workers boot.Phase 1: Proof of Concept
json_encode() in a test controller with StreamedResponse.Phase 2: API Integration
JsonStreamer in a JsonStreamerService and roll it out controller-by-controller.php artisan optimize exceeds the Phase 0 memory baseline (catches compiler-pass resource regressions early).Phase 3: Async & CLI
finally blocks.Phase 4: Real-Time (optional / experimental)
v8.1.0-BETA3 and v8.1.9, all backward compatible. Expect routine composer update hygiene rather than migration work.read/write + emitter) is small. Internal runbook should document the container-rebuild step as the first troubleshooting action for any streaming-related post-deploy anomaly.ulimit -n and PHP-FPM/Octane worker counts accordingly.| Mode | Trigger | Signal | Mitigation |
|---|---|---|---|
| Container compile failure | Pass ordering conflict with a third-party bundle | artisan optimize fatal at deploy |
Pin ^8.1.9; validate in CI with representative packages installed |
| Stale compiled container | Deploy without cache clear after version bump | Streamer behaves per pre-fix semantics | Force optimize:clear on package version change |
| Resource/fd exhaustion | Handles not closed in Octane/queue workers | Sporadic 500s under load; rising lsof fd count |
try/finally stream closure; soak test |
| Stream resource retention during build | New v8.1.9 behaviour under many passes | CI build memory/time drift | Baseline + threshold gate in CI |
| Malformed/partial JSON | Network interruption, fuzzed input | Truncated payloads, unhandled exceptions | Explicit error handling around read() |
| Memory regression | Deeply nested / recursive object graphs | Memory ceiling reached | Regression fixtures; monitor the leak-fix areas |
| Eloquent serialization mismatch | Casts, accessors, hidden attributes | Wrong payload shape | Contract tests on representative models |
read/write API is a two-method surface; a Laravel developer can be productive in under a day, and the existing Serializer familiarity transfers directly.How can I help you explore Laravel packages today?