Unofficial PSR7 FAQ

What is PSR7?

PSR7 is an attempt to reinvent and harmonize Request and Response proposed by PHP Framework Interop Group.

What is PSR7 not?

PSR7 is not a common denominator of existing HTTP libraries.

Where can I find official PSR7 documentation?

Why bother?

HTTP is the heart of every web project out there and nearly every php-fig member voted in favor of this PHP Standard Recommendation.

Still, can I ignore it?

At some point you inevitable stumble over PSR7 as nearly all major PHP projects will have some sort of PSR7 support.

Can PSR7 get deprecated and replaced in the near-term?

Considering the long development time of PSR7 it’s unlikely. Furthermore projects need even more time to readopt and release new versions. It’s of good use to engage and learn about PSR7 now.

Can I use project X and not care about PSR7 details?

No, PSR7 is invasive. If you work with PSR7 compliant HTTP Messages you need to know the philosophy and ideas behind PSR7 design decisions.

Where can I find those?

In the Meta Document.


Functional Programming

What functional programming concepts are used?

Functions without side-effects: No observable interaction with calling functions or the outside world beside returning a value.

What functional programming concepts are not used?

Immutability is not used as PHP does not offer this feature. Most implementations even modify objects after creation by accessing private properties.

Could an interface ensure immutability?

No, suchlike characteristics can only be implemented and enforced by external supervisor (layer/runtime/…).

Separate specialized interfaces for write methods were scrapped on the way with somewhat absurd argument about too many interfaces.

How to change data in PSR7 objects?

By using mutator methods defined by PSR7.

What are mutator methods?

Mutator method is a method changing data. e.g.:

	->withHost($host)
	->setName($name)
	->replaceFooWithBar($foo, $bar)

Can I omit mutator methods?

No, there is no segregation between read and write in PSR7. You have to implement them even on readonly objects. In fact readonly objects are implicitly forbidden. You could do no-op or throw exceptions but this violates LSP.

What mutator methods are defined by PSR7?

Only methods without side-effects are defined by PSR7.

	public function withHeader($name, $value);
	public function withoutHeader($name);

How to implement side-effect free mutators?

Create new instance and reassign data from old object. Cloning old object is easy and efficient way to do so:

	public function withHost($host)
	{
		$new = clone $this;
		$new->host = $host;
		return $new;
	}

some alternatives:

	$new = clone $this;
	$new = new self(...)
	$new = new static(...)
	$new = new MyClass(...)
Can I implement my own mutator methods?

Shure, other PSR7 aware projects simply ignore those.

Can I use PHP’s pass-by-reference-semantics to propagate object changes back to caller?

No, changes may not affect instance in caller. You should return the newly created object. You can implement additional mutators non-violating interface contract. e.g. ->setHost($host);

What to do for changes to take effect?

Change your code flow. PSR7 is invading you.

	function changeFoo($request, $response) {
		$request = $request->withUri(new Uri('https://example.org/'));
		$response = $response->withStatus(200, 'OK');
		
		// return changes to outer scope
		return array($request, $response);
	}
	list ($req2, $res2) = changeFoo($req, $res);
	// $req, $res are unchanged
	// $req2, $res2 are fooChanged

How to implement PSR7 support in existing codebase?

Transform your objects on project boundaries to some PSR7 implementation and vice versa. Bridge/Wrapper/Proxy/you-name-it look here and here


Streams

Are mutator methods on StreamInterface side-effect free?

No, streams are a special case breaking this PSR7 convention.

Why StreamInterface methods are allowed to have side-effects?

A stream is defined as “data elements made available over time”. So by definition there is a side-effect over time even for readonly streams while read in data. Immutable objects cannot be changed after creation at no time, so streams cannot be immutable.

Official explanation: Why are streams mutable?

Is there a way to access header values from “Chunked Trailer Part”?

No, PSR7 does not specify any way to access header values from “Chunked Trailer Parts”.

What to expect from getBody() on messages without body content (HEAD, GET request, 204)?

no-op instance of StreamInterface (php://memory)


Value Objects

What are Value Objects?

Objects without explicit identity. e.g.: 20 ikea coffee cups

Is this my coffee or yours?

No way to know.

Does PSR7 define identity?

Yes, “Uniform Resource Identifier” (URI) is defined by UriInterface.

Why only PSR7 Requests have an identity?

PSR7 define HTTP Messages as on the wire, consequently omit common methods from point-of-view of a PSR7 consumer. So there is no way to access the final URI of a redirected response.

Can URI be used to identify Messages of other type?

Yes, always implement getUri() on all message types. URIs are solid base to identify, validate and compare http resources. All of HTTP is unthinkable without URIs.


URIs

What can I expect from instance of UriInterface?

not NULL, empty string

Can I expect any info to be available in instance of UriInterface?

No. There is no guarantee any data is available.

Default Scheme?

not NULL, empty string

Default port?

NULL (not integer!)

What is the default path?

empty string (because of bugs in arbitrary frontcontrollers losing context)

How to achieve a solid Uri implementation?

Fill in sane defaults for missing values in constructor.

	default scheme: http
	default host: 0.0.0.0
	default port: 80
	default path: /
	empty string as default for all other parts

minimum valid URI:

	"http://0.0.0.0/" === (new Uri())->__toString()

Can and should request-targets be derived from data in UriInterface?

Yes. PSR7 does not define any methods to do so, however. Implement those methods in Uri definition:

	public function originForm(); // absolute-path [ "?" query ]
	public function absoluteForm(); // alias for ->__toString()
	public function authorityForm(); // alias for ->getAuthority()
	public function asteriskForm(); // always: *

usage:

	$request = $request->withRequestTarget($uri->originForm())

For implementation details see: 5.3. Request Target

Valid values for Host?
	127.0.0.1
	[::1]
	localhost
	a
	foo.bar

Middleware

What is “Middleware”?

Buzzword for “passing messages around” in contrast to “calling methods”.

There are way more definitions nor specific nor related to PSR7: MOM, 1, 2, EDA

What is not “Middleware”?

Onion layers are not Middleware.

Is “attributes” property of ServerRequestInterface a good replacement for Registry pattern?

No, faking global state by “attributes” property is as evil as real global state. Everyone can change this attributes at any time and place. It’s abusing HTTP Request as a trashcan. Define your dependencies explicit in method signature.


Interoperability


Interfaces

What interfaces are defined by PSR7?

Can I implement only one of those interfaces?

Yes. Here is dependency graph:

	UriInterface
			methods:	16
			dependencies:	-
	StreamInterface
			methods:	15
			dependencies:	-
	MessageInterface
			methods:	11
			dependencies:	StreamInterface
	ResponseInterface
			methods:	3
			dependencies:	MessageInterface, StreamInterface, UriInterface
	RequestInterface
			methods:	6
			dependencies:	MessageInterface, StreamInterface, UriInterface
	ServerRequestInterface
			methods:	13
			dependencies:	MessageInterface, RequestInterface, StreamInterface, UriInterface
	UploadedFileInterface
			methods:	6
			dependencies:	StreamInterface

method list

Immutability, it turns out, has costs. High costs. (for PHP’s garbage collector)