response-interop / impl
Reference implementations of the Response-Interop interfaces.
Requires
- php: >=8.4
- response-interop/interface: ^1.0
Requires (Dev)
- pds/composer-script-names: ^1.0
- pds/skeleton: ^1.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- pmjones/php-styler: 0.x@dev
This package is auto-updated.
Last update: 2026-08-17 16:42:07 UTC
README
Reference implementations of the Response-Interop interfaces for PHP 8.4+.
Installation
Install this package via Composer:
composer require response-interop/impl
Usage
Build a ResponseStruct, populate it, and hand it to a ResponseSenderService:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\ResponseSender; $response = new Response(); $response->headers->setHeader('content-type', 'text/plain'); $response->body = 'Hello, world!'; (new ResponseSender())->sendResponse($response);
Every Response property is also a promoted constructor argument; its defaults
are:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\ResponseHeaders; $response = new Response( httpVersion: '1.1', statusCode: 200, headers: new ResponseHeaders(), body: '', );
ResponseSender writes to php://output by default. Pass any writable
resource to send elsewhere, such as a buffer to capture output in tests:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\ResponseSender; $buffer = fopen('php://memory', 'wb+'); /** @var Response $response */ (new ResponseSender($buffer))->sendResponse($response); rewind($buffer); $sent = stream_get_contents($buffer);
Set a cookie:
use ResponseInterop\Impl\Response; /** @var Response $response */ $response->headers->setCookie('session', 'abc123', [ 'path' => '/', 'httponly' => true, 'samesite' => 'Lax', ]);
The body accepts a string, any Stringable, or a
ResponseBodyHandler that prepares its own headers and streams its own
content. This package ships two handlers; implement the interface for your own.
Send a JSON body:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\JsonResponseBody; /** @var Response $response */ $response->body = new JsonResponseBody(['hello' => 'world']);
The optional arguments customize the output:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\JsonResponseBody; /** @var Response $response */ $response->body = new JsonResponseBody( data: ['hello' => 'world'], type: 'application/hal+json', flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR, depth: 512, );
$type sets the content-type (default application/json); $flags and
$depth pass through to json_encode(), defaulting to an HTML-safe flag set
with JSON_THROW_ON_ERROR and a depth of 512. Passing $flags replaces the
default set entirely; re-include JSON_THROW_ON_ERROR and the HTML-safe flags
to keep them.
Send a file:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\FileResponseBody; /** @var Response $response */ $response->body = new FileResponseBody(new SplFileObject('/path/to/file.pdf'));
The optional arguments set the response headers, defaulting from the file itself:
use ResponseInterop\Impl\Response; use ResponseInterop\Impl\FileResponseBody; /** @var Response $response */ $response->body = new FileResponseBody( file: new SplFileObject('/path/to/report.pdf'), type: 'application/pdf', encoding: 'binary', disposition: 'attachment', filename: 'report.pdf', );
$type sets the content-type (default application/octet-stream),
$encoding the content-transfer-encoding (default binary), and
$disposition/$filename the content-disposition (default attachment
using the file's own name). A content-length header is added from the file
size.
Classes
| Interface | Implementation |
|---|---|
| ResponseStruct | Response |
| ResponseHeadersCollection | ResponseHeaders |
| ResponseBodyHandler | FileResponseBody, JsonResponseBody |
| ResponseCookieHelperService | ResponseCookieHelper |
| ResponseSenderService | ResponseSender |
| ResponseBodySenderService | ResponseSender |
| ResponseThrowable | ResponseException |
All classes are in the ResponseInterop\Impl namespace.
Errors
Every exception thrown by this package implements the ResponseThrowable marker
interface. Catch that instead of the concrete ResponseException for
portability across implementations:
use ResponseInterop\Impl\Response; use ResponseInterop\Interface\ResponseThrowable; try { /** @var Response $response */ $response->headers->setHeader('content-type', ''); } catch (ResponseThrowable $e) { // handle the blank header value }
ResponseHeaders throws on an invalid or empty header field name, a blank
header value, a blank cookie name, or an unparseable set-cookie string.
ResponseSender throws on a negative length or offset, or on a read or seek
failure, when sending a body from a stream resource.
See the Response-Interop interface package for the full specification.