PSR-7 overview — MessageInterface, RequestInterface, ResponseInterface
Intermediate5 min read·fw-04-001
psr
Concept
PSR-7 (PHP-FIG standard) defines HTTP message interfaces. It's a standard that allows HTTP client libraries, framework components, and middlewares to interoperate without depending on each other's concrete classes.
Core interfaces:
MessageInterface: Base for both request and response. Methods:getProtocolVersion(),getHeaders(),getHeader(string $name),getBody(),withHeader(string $name, string $value),withBody(StreamInterface $body).RequestInterface extends MessageInterface:getMethod(),getUri(),withMethod(string $method),withUri(UriInterface $uri).ServerRequestInterface extends RequestInterface: Adds server-side data:getServerParams(),getCookieParams(),getQueryParams(),getParsedBody(),getUploadedFiles(),getAttributes().ResponseInterface extends MessageInterface:getStatusCode(),getReasonPhrase(),withStatus(int $code, string $reasonPhrase = '').StreamInterface: Represents a body as a stream.read(),write(),seek(),tell(),eof(),getContents().UriInterface: Represents a URI.getScheme(),getHost(),getPath(),getQuery(),withPath(), etc.UploadedFileInterface: Represents a file upload.getStream(),moveTo(),getSize(),getError(),getClientFilename().
Immutability: PSR-7 messages are immutable. with*() methods return a NEW instance with the modification. This prevents shared mutable state bugs in middleware.
Why PSR-7: Middleware that works with any PSR-7 implementation can be shared across Slim, Laminas, and any compliant framework.
Code Example
php
<?php
// PSR-7 in practice — using nyholm/psr7 (lightweight PSR-7 implementation)
// composer require nyholm/psr7 nyholm/psr7-server
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7Server\ServerRequestCreator;
// Creating a ServerRequest from PHP superglobals
$factory = new Psr17Factory();
$creator = new ServerRequestCreator($factory, $factory, $factory, $factory);
$request = $creator->fromGlobals();
// Reading the request
$method = $request->getMethod(); // 'GET'
$path = $request->getUri()->getPath(); // '/users/42'
$query = $request->getQueryParams(); // ['page' => '2']
$body = $request->getParsedBody(); // POST data (associative array)
$headers = $request->getHeaders(); // ['Content-Type' => ['application/json']]
$server = $request->getServerParams(); // $_SERVER equivalent
$attrs = $request->getAttributes(); // framework-added data (route params, etc.)
// Immutable — with* methods return new instance
$modified = $request->withMethod('POST')
->withHeader('X-Custom', 'value');
// $request unchanged, $modified has the modifications
// Building a response
$response = $factory->createResponse(200)
->withHeader('Content-Type', 'application/json');
$body = $factory->createStream(json_encode(['user' => ['id' => 42, 'name' => 'Alice']]));
$response = $response->withBody($body);
// Emitting the response (send to browser)
// Status line
http_response_code($response->getStatusCode());
// Headers
foreach ($response->getHeaders() as $name => $values) {
foreach ($values as $value) {
header("{$name}: {$value}", false);
}
}
// Body
echo $response->getBody()->getContents();