← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

PSR-17: HTTP Factories

Style PHP 7.1+ Intermediate
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5) — deptrac and phpstan (listed in detection_hints.tools) can detect direct instantiation of concrete PSR-7 classes via architecture rules, but it's not a default lint.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3) — quick_fix says inject factory interfaces instead of instantiating concrete classes; it's a pattern replacement but typically touches constructors and call sites across a component.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3) — applies to HTTP-handling code; the factory abstraction is a small persistent commitment for the HTTP layer but doesn't shape the whole system.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5) — the misconception (confusing PSR-17 as an extension of PSR-7 rather than a companion factory standard) is a well-documented gotcha that most PHP devs eventually learn.

About DEBT scoring →

Also Known As

PSR-17 HTTP factories PSR RequestFactoryInterface

TL;DR

Standard factory interfaces for creating PSR-7 HTTP objects — decoupling library code from any specific PSR-7 implementation.

Explanation

PSR-17 provides factory interfaces for every PSR-7 type: RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, and UriFactoryInterface. By accepting a PSR-17 factory rather than hard-coding new GuzzleHttp\Psr7\Response(), library code works with any PSR-7 implementation. Particularly valuable in middleware and framework internals that construct HTTP messages. Implementations include nyholm/psr7 (fastest, smallest) and guzzlehttp/psr7. PSR-17 completes the HTTP abstraction layer begun by PSR-7 and extended by PSR-15.

Common Misconception

PSR-17 is an extension of PSR-7. PSR-17 is a companion standard that defines factory interfaces for creating PSR-7 objects — without PSR-17, libraries that need to create request/response objects had to depend on specific PSR-7 implementations rather than an abstract factory.

Why It Matters

PSR-17 defines HTTP message factory interfaces — code that uses RequestFactoryInterface and ResponseFactoryInterface can create HTTP objects without depending on a specific PSR-7 implementation.

Common Mistakes

  • Instantiating PSR-7 objects directly (new GuzzleHttp\Psr7\Request()) — tightly couples to one library.
  • Not injecting factories — hardcoded factory calls prevent swapping PSR-7 implementations.
  • Confusing PSR-7 (HTTP message interfaces) with PSR-17 (factory interfaces for creating them).
  • Not using a discovery package — manually resolving which factory implementation is installed.

Code Examples

✗ Vulnerable
// Direct PSR-7 instantiation — coupled to Guzzle:
$request = new GuzzleHttp\Psr7\Request('GET', $url);

// PSR-17 factory — implementation-agnostic:
public function __construct(private RequestFactoryInterface $factory) {}
$request = $this->factory->createRequest('GET', $url);
// Swap Guzzle for Nyholm PSR-7 by changing one DI binding
✓ Fixed
// PSR-17 HTTP Factories — create PSR-7 message objects
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;

// Inject factories rather than instantiating directly
class OrderController {
    public function __construct(
        private ResponseFactoryInterface $responseFactory,
        private StreamFactoryInterface $streamFactory,
    ) {}

    public function show(int $id): ResponseInterface {
        $order  = Order::findOrFail($id);
        $body   = $this->streamFactory->createStream(json_encode($order));
        return $this->responseFactory->createResponse(200)
            ->withHeader('Content-Type', 'application/json')
            ->withBody($body);
    }
}

// Implementations: nyholm/psr7, guzzlehttp/psr7, laminas-diactoros

Tags


Added 15 Mar 2026
Edited 22 Mar 2026
Views 53
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 2 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M
No pings yet today
No pings yesterday
Amazonbot 6 ChatGPT 6 SEMrush 5 Ahrefs 4 Scrapy 2 Brave Search 2 Perplexity 1 Google 1 Claude 1 Meta AI 1 PetalBot 1 Twitter/X 1 Applebot 1 Bing 1
crawler 29 crawler_json 4
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Low
⚡ Quick Fix
Inject PSR-17 factories (RequestFactoryInterface, ResponseFactoryInterface) instead of instantiating concrete HTTP classes — this makes your code testable and framework-agnostic
📦 Applies To
PHP 7.1+ web api cli
🔗 Prerequisites
🔍 Detection Hints
new GuzzleHttp\Psr7\Response() directly instead of ResponseFactoryInterface; framework-specific HTTP object creation preventing portability
Auto-detectable: ✓ Yes phpstan deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: File


✓ schema.org compliant