laminas/laminas-httphandlerrunner
Laminas HTTP Handler Runner executes PSR-7 request handlers and PSR-15 middleware, emitting generated responses to the client in traditional PHP server environments.
Framing correction (important for stakeholders): this is not a Laravel package. It is a Laminas-maintained, framework-agnostic PSR-7/PSR-15 runtime utility: it marshals a ServerRequestInterface, invokes a RequestHandlerInterface (typically a middleware pipeline), and emits the resulting response through a SAPI emitter. There is no service provider, no facade, no config file, and no Laravel integration surface. Any evaluation must therefore be about narrow, deliberate adoption inside or alongside a Laravel estate, not about plugging it into Laravel's HTTP kernel.
Architecture fit
RequestHandlerRunner (+ RequestHandlerRunnerInterface), EmitterInterface, SapiEmitter, SapiStreamEmitter, EmitterException. Roughly a bootstrap-and-emit concern, not a framework.Illuminate\Http\Request/Response and its own kernel and middleware contract.SapiStreamEmitter, which flushes headers/status before streaming the body, useful for large file downloads and progressive responses — and the EmitterException diagnostics (headers_sent filename/line), which materially shorten debugging of "output already started" incidents.Integration feasibility
composer require), BSD-3-Clause (permissive, compatible with proprietary code), typed and Psalm-annotated, PHP 8.x current through 8.4 support.SapiEmitter. Low blast radius, immediate value.public/index.php uses RequestHandlerRunner, sharing the repo/deploy pipeline but not Laravel's process model. Clean separation, no kernel contention.Illuminate and PSR-7 objects) is possible with third-party shims but adds a conversion layer, duplicate middleware semantics, and a class of subtle request/response fidelity bugs. Treat as a last resort.Technical risk
function_exists-style checks fixed early, exception paths hardened.@final "in preparation for the next major" — an explicit signal that a v3 with BC breaks is planned. Pin to ^2.x and budget a small upgrade task.Key questions
php://output and will not behave correctly under worker runtimes without a different EmitterInterface implementation.Throwable → 500 path? The runner converts exceptions to responses; if we adopt it, we must wire our own logging/APM middleware or we will lose observability.Stack fit
SapiEmitter/SapiStreamEmitter for streaming and file emission where response()->streamDownload() is insufficient. Everything else stays native Laravel.laminas/laminas-diactoros as the PSR-7/PSR-17 implementation (the package's own test suite favors it) and a PSR-11 container for handler wiring.Migration path
public/index.php running a three-middleware PSR-15 pipeline behind a feature-flagged route; confirm emitter behavior for normal, streamed, and error responses.StreamedResponse, BinaryFileResponse analogues) on memory and time-to-first-byte for a 500 MB download.ResponseEmitter) so the third-party type does not leak into domain code.Compatibility
psr/http-message ^1.1|^2, psr/http-server-handler, psr/http-server-middleware; 2.6.0+ added PSR-7 v2 support and expanded the message-implementation requirement. Verify no constraint conflict with Laravel's existing PSR-7 dependencies (Nyholm, Guzzle PSR-7) before committing.^2.12 and record the planned v3 review as a tracked task.Sequencing
Maintenance
headers_sent.Support
Scaling
SapiStreamEmitter is the scaling win: constant-memory streaming of large bodies versus buffering whole responses, which reduces per-worker memory and improves TTFB under concurrency.Failure modes
EmitterException::forHeadersSent — headers already flushed by stray echo/BOM/whitespace; surfaces filename and line, which is the package's most useful operational feature.ob_start, gzip handlers) corrupting or truncating streamed responses.Content-Length in streamed responses causing truncated downloads behind proxies.Ramp-up
StreamedResponse.How can I help you explore Laravel packages today?