PSR Adapters
Introduction
A group called The PHP Framework Interop Group (FIG) came together to try and solve some of the issues with reusing components between frameworks. For example, most frameworks tend to write their own HTTP requests, responses, DI containers, etc. Having many different implementations to solve the same thing makes it difficult to build libraries that could work across frameworks. So, the FIG set about introducing some standards called PSRs to simplify reusing these components across frameworks.
For reasons we'll discuss in the next section, Aphiria does not use most PSRs natively. However, we do offer adapters for PSR-7 and PSR-11 to make it possible to convert Aphiria models to PSR-compliant models and vice versa.
Why Doesn't Aphiria Adopt All The PSRs?
A lot of major frameworks, eg Symfony and Laravel, have also decided not to adopt some PSRs. For example, PSR-7 has been pretty widely criticized for the following reasons:
- Requests and responses are immutable, which was seen as a poor application of immutability
- It's all too easy to forget to get the new instance from any
with*()
methods, leading to bugs - Inconsistencies in some of the internals of PHP and the PSR make it impossible to achieve true immutability
- It's all too easy to forget to get the new instance from any
- HTTP message bodies are not inherently streams - they should be readable as streams
ServerRequestInterface
too closely mirrors some PHP superglobals, for better or for worse- It relies on PHP
$_SERVER
and$_FILES
structures, which are full of idiosyncrasies
- It relies on PHP
These negatives aside, PSR-7 did do a decent job in some of its modeling of HTTP messages. In fact, some of Aphiria's message models are somewhat similar to PSR-7, but attempt to improve their shortcomings.
PSR-11 was too limiting, eg no targeted bindings, and didn't provide enough value to justify supporting it.
PSR-7
PSR-7 is focused on creating a standard for HTTP messages, URIs, streams, and uploaded files. For those that wish to use third party libraries that only support PSR-7, we've created an easy way to convert to and from PSR-7 via Psr7Factory
.
use Aphiria\PsrAdapters\Psr7\Psr7Factory;
use Nyholm\Psr7\Factory\Psr17Factory;
// This third party factory can create all PSR-7 models for us
$psr17Factory = new Psr17Factory();
$psr7Factory = new Psr7Factory(
psr7RequestFactory: $psr17Factory,
psr7ResponseFactory: $psr17Factory,
psr7StreamFactory: $psr17Factory,
psr7UploadedFileFactory: $psr17Factory,
psr7UriFactory: $psr17Factory
);
We'll use this factory in the examples below.
Requests
Create a PSR-7 request from an Aphiria request:
$psr7Request = $psr7Factory->createPsr7Request($aphiriaRequest);
Create an Aphiria request from a PSR-7 request:
$aphiriaRequest = $psr7Factory->createAphiriaRequest($psr7Request);
Responses
Create a PSR-7 response from an Aphiria response:
$psr7Response = $psr7Factory->createPsr7Response($aphiriaResponse);
Create an Aphiria response from a PSR-7 response:
$aphiriaResponse = $psr7Factory->createAphiriaResponse($psr7Response);
Streams
Create a PSR-7 stream from an Aphiria stream:
$psr7Stream = $psr7Factory->createPsr7Stream($aphiriaStream);
Create an Aphiria stream from a PSR-7 stream:
$aphiriaStream = $psr7Factory->createAphiriaStream($psr7Stream);
URIs
Create a PSR-7 URI from an Aphiria URI:
$psr7Uri = $psr7Factory->createPsr7Uri($aphiriaUri);
Create an Aphiria URI from a PSR-7 URI:
$aphiriaUri = $psr7Factory->createAphiriaUri($psr7Uri);
Uploaded Files
Create PSR-7 uploaded files from an Aphiria request:
$psr7UploadedFiles = $psr7Factory->createPsr7UploadedFiles($aphiriaRequest);
PSR-11
PSR-11's aim was to give a simple interface for dependency injection containers to implement. Although IContainer
does not natively support PSR-11, it's trivial to create a container that does.
Creating a PSR-11 Container
use Aphiria\DependencyInjection\Container;
use Aphiria\PsrAdapters\Psr11\Psr11Container;
$aphiriaContainer = new Container();
$psr11Container = new Psr11Container($aphiriaContainer);
if ($psr11Container->has(Foo::class)) {
$foo = $psr11Container->get(Foo::class);
}