PSR7 BRIDGE
vslim / vhttpd PSR-7 Bridge Plan
This document describes how vhttpd, php-worker.php, and vslim should evolve so that
vhttpd can serve as a more generic HTTP runtime for the PHP ecosystem while vslim
keeps a lightweight native V request/response core.
Goal
We want these three properties at the same time:
vhttpdshould stay generic and not be hard-coded tovslimroute semantics.- PHP frameworks and middleware that expect PSR-7 should be usable behind
vhttpd. vslimshould keep a small, mutable, V-friendly core model instead of immediately becoming a full immutable PSR-7 implementation.
The result is a layered design:
HTTP client
-> vhttpd transport/runtime
-> request envelope
-> php-worker bridge
-> PSR-7 adapter (optional)
-> vslim adapter or other PHP framework
Why not implement PSR-7 directly in the extension first?
PSR-7 is interface-only. The php-fig/http-message package defines interfaces, not a concrete
implementation. See:
A direct extension-level implementation would immediately require:
- immutable
with*()semantics StreamInterfaceUriInterfaceUploadedFileInterface- normalized request attributes/body/cookies/server params
That is a much larger project than what vslim needs right now.
Recommended architecture
Layer 1: vhttpd owns transport
vhttpd should parse network traffic and turn it into a complete request envelope.
It should not try to model PHP framework semantics.
Recommended envelope fields:
methodpathprotocol_versionschemehostportheaderscookiesquerybodyremote_addrserveruploaded_filesattributes
Notes:
- Transport should stay structured and array-based across
vhttpd -> php-worker -> vslim. - This keeps
veb-derived request data intact and avoids a second JSON compatibility shape. - Additional fields can still be added later without changing the high-level architecture.
Layer 2: php-worker owns PHP ecosystem adaptation
php-worker.php should be the place where transport envelopes are adapted into PHP-facing
runtime objects.
This layer can choose one of two paths:
- If a PSR-7 implementation is available, build a real
ServerRequestInterface. - Otherwise, keep using the native
vslim_handle_request($envelope)path.
This means php-worker becomes the compatibility seam between:
- generic transport (
vhttpd) - PHP ecosystem semantics (PSR-7/PSR-15/frameworks)
Layer 3: vslim keeps a native core and adds adapters
vslim should keep:
VSlim\RequestVSlim\ResponseSlimApp- middleware chain
- route matching
These remain mutable and compact.
On top of that, vslim can later add adapter entry points:
from_psr7(ServerRequestInterface $request)to_psr7_response(VSlim\Response $response)- or a PHP-side adapter class that translates between PSR-7 and
vslim_handle_request(...)
This lets vslim participate in PSR-7 workflows without forcing the internal model to copy PSR-7.
Phase plan
Phase 1: complete the transport envelope
Deliverables:
vhttpdemits a richer request envelopephp-workerkeeps forwarding tovslim_handle_request(...)vslimcontinues to consume the envelope directly
At this stage, vslim gains better request fidelity without taking on PSR-7 complexity.
Phase 2: worker-side PSR-7 construction
Deliverables:
- detect installed PSR-7 implementation in PHP worker
- create a real
ServerRequestInterface - allow worker-side apps to be written in PSR-7/PSR-15 style
Examples of implementations that may be supported by userland:
- Nyholm PSR-7
- Guzzle PSR-7
- Laminas Diactoros
vhttpd still stays generic; only the worker changes.
Phase 3: vslim adapter layer
Deliverables:
- define a
vslimadapter that can read a PSR-7 request and produce aVSlim\Response - optionally define a PSR-7 response adapter for outgoing responses
This can live either:
- in PHP userland beside
php-worker.php, or - partially inside
vslimas exported helper APIs
Phase 4: optional native PSR-7 implementation
Only do this if the project later proves it is worth it.
Reasons to delay this:
- high implementation cost
- lots of edge cases
- adapter approach already unlocks framework compatibility
Suggested responsibilities
vhttpd
Responsible for:
- HTTP parsing
- connection management
- request envelope creation
- proxying requests to worker
- lifecycle and observability
Not responsible for:
- PSR-7 object semantics
- framework routing semantics
- message immutability
php-worker.php
Responsible for:
- adapting envelope -> PHP runtime request form
- optional PSR-7 request creation
- dispatching to
vslimor another app - serializing response back to
vhttpd
vslim
Responsible for:
- routing and middleware
- native request/response model
- adapter hooks for PSR-7 later
Not responsible for:
- raw network IO
- socket supervision
- full PSR-7 implementation in phase 1
Proposed request envelope v2
Minimal recommended shape:
[
'method' => 'GET',
'path' => '/users/42?trace_id=worker',
'body' => '',
'scheme' => 'https',
'host' => 'example.test',
'port' => '443',
'protocol_version' => '1.1',
'remote_addr' => '127.0.0.1',
'headers' => ['x-request-id' => 'abc'],
'cookies' => ['sid' => 'cookie-7'],
'query' => ['trace_id' => 'worker'],
'server' => ['REQUEST_TIME_FLOAT' => '...'],
'uploaded_files' => [],
'attributes' => [],
]
Notes:
pathcan remain the canonical request target.queryis still useful even if query is also embedded inpath; it avoids reparsing later.attributesmaps cleanly to PSR-7 request attributes and also to route params.
Suggested PHP worker strategy
Pseudo-flow:
if (function_exists('vslim_handle_request')) {
// native fast path
return vslim_handle_request($envelope);
}
if ($psr7FactoryIsAvailable) {
$request = buildServerRequestFromEnvelope($envelope);
return $app($request); // or PSR-15 dispatch
}
// fallback legacy dispatch
return dispatchLegacy($envelope);
This lets the worker support both:
vslimnative mode- broader PSR-7 app mode
Suggested vslim adapter API
Native core should stay close to what we already have.
Later adapters may look like:
$adapter = new VPhp\VSlim\Psr7Adapter($app);
$response = $adapter->handle($serverRequest);
or:
$envelope = VPhp\VSlim\Psr7Adapter::toEnvelope($serverRequest);
$raw = vslim_handle_request($envelope);
$response = VPhp\VSlim\Psr7Adapter::toResponse($raw, $responseFactory, $streamFactory);
The second version is especially attractive because it does not require the extension to own full PSR-7 semantics.
Current recommendation
The next implementation steps should be:
- enrich the request envelope in
vhttpd - mirror those fields into
VSlim\Request - make
php-worker.phpable to build a PSR-7 request when userland provides a PSR-7 implementation - add a small adapter layer around
vslim_handle_request(...)
This keeps the system incremental and avoids prematurely forcing vslim to become a full
PSR-7 library.