-
Notifications
You must be signed in to change notification settings - Fork 0
Emitter
InitPHP\HTTP\Emitter\Emitter converts a PSR-7 ResponseInterface into bytes on the wire under any SAPI that exposes header() and stdout — PHP-FPM, mod_php, the built-in CLI server, FrankenPHP.
use InitPHP\HTTP\Emitter\Emitter;
(new Emitter())->emit($response);That's everything for the common case. The emit() call does these things in order:
-
Output sanity check (strict mode only). If anything has already been written or
header()has already been called, the emitter throws — better than silently sending a corrupt response. -
Status line.
header("HTTP/1.1 200 OK", true, 200). -
Headers. Every entry from
$response->getHeaders()becomes aheader()call. Names are normalised to title-case-with-dash (x-trace-id→X-Trace-Id);Set-Cookieis the one allowed-to-repeat header (subsequent values usereplace = false). -
Body. The whole body is
echo-ed in one go, or streamed in chunks if you pass a buffer length.
$emitter = new Emitter(/* strictMode: */ true); // defaultWhen strict mode is on:
-
headers_sent($file, $line)is checked first; iftrue, the emitter throwsEmitHeaderExceptionnaming the file and line that flushed prematurely. - The active output buffer (if any) is inspected; non-empty buffers raise
EmitBodyException.
Turn strict mode off only when you're integrating with something that already wrote partial output (e.g. a legacy script that echo-ed before passing control to your framework):
$emitter = new Emitter(/* strictMode: */ false);
$emitter->emit($response);namespace InitPHP\HTTP\Emitter\Exceptions;
class EmitHeaderException extends \RuntimeException { ... }
class EmitBodyException extends \RuntimeException { ... }| Exception | Cause | Typical fix |
|---|---|---|
EmitHeaderException |
headers_sent() returned true |
Find the early echo / BOM / un-suppressed warning |
EmitBodyException |
Output buffer has un-flushed content |
ob_clean() before emit, or unwind the buffering layer |
Both extend \RuntimeException, so a single catch is fine if you don't care which side fired:
try {
(new Emitter())->emit($response);
} catch (\RuntimeException $e) {
error_log($e->getMessage());
}v2 → v3 note: v2 always raised
EmitBodyExceptionfor both failure modes, so callers couldn't distinguish "headers already flushed" from "output buffer dirty". v3 splits the two.
The default body emission echo-es the body in one go, after calling __toString() (which rewinds the stream if seekable):
$emitter->emit($response);That's fine for small responses. For multi-MB bodies, hand emit() a chunk size:
$emitter->emit($response, /* bufferLength: */ 8192);This switches to a chunked path that streams the body in bufferLength-byte slices — covered in Chunked Bodies.
When the response carries a Content-Range: bytes <first>-<last>/<total|*> header and you're using the chunked path, only the requested range is emitted — covered in Content-Range.
The facade lazily resolves a shared Emitter instance:
use InitPHP\HTTP\Facade\Emitter;
Emitter::emit($response);
Emitter::emit($response, 8192);See Facades.
-
Chunked Bodies —
bufferLengthtuning for large responses. - Content-Range — partial-content / byte-range responses.
- Recipe — Streaming Large Files — file download patterns end-to-end.
initphp/http · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
PSR-7 Messages
PSR-17 Factories
PSR-18 Client
Emitter (SAPI)
Static Facades
Recipes
Reference
Migration & Help