PSR-7 vs. the Server(Request|Response) RFC

tl;dr: PSR-7 aims to model HTTP messages, whereas the RFC aims to make some non-OO PHP functionality more OO-ish.


I had thought the distinction between the purpose of PSR-7, and the purpose of the server-side request/response object RFC, was obvious from their descriptions. But that is apparently not the case.

I would prefer to discuss the RFC entirely on its own merits, and not dwell on the various strengths and weaknesses of PSR-7. However, to reduce confusion on this topic, I am happy to take some time to expound on the differences.

To understand those differences more clearly, we need to start with a history of PSR-7.

Purpose of PSR-7

PSR-7 was born to answer the question, “How can we model HTTP messages in PHP for sending a request, and getting back a response?” That is, how can we standardize the model of an HTTP request message for sending, and the model of the returned the HTTP response, when using PHP as an HTTP client?

The entrance vote passed in Jan 2014 after about a year of pre-work, with Michael “Guzzle” Dowling as lead: https://groups.google.com/d/topic/php-fig/H1Lr7FYxj94/discussion. You can see the original draft at https://github.com/php-fig/fig-standards/pull/244/files.

What you’ll find in the draft is one pair of request/response interfaces, descended from a message interface, with stream as message body, and no URI specification. These were designed primarily as client interfaces; all the referenced projects in the draft were client-side. (As a side note, they were mutable. Dowling said, “Having mutable and immutable messages would add a significant amount of complexity to a HTTP message PSR and would not reflect what is currently being used by a majority of PHP projects.”)

After 8 months, Dowling stepped down in August 2014, citing a lack of time and motivation. He also said: “I don’t think there’s one way to represent HTTP messages, clients, or servers in PHP.” https://groups.google.com/forum/#!topic/php-fig/XwFcqSmqzGk

Shortly thereafter, in September 2014, with encouragement from many (including myself), MWOP of Zend Framework takes over PSR-7. We learn that he has “Sencha Connect” and middleware on the brain:

The reason I wanted to port Connect is this: an application consists of middleware. Each middleware is a callback that accepts a request, response, and a callback called “next” (which is optional, actually):

function (request, response, next)

I know from Michael Dowling that the original intent for PSR-7 was to define HTTP messages that could then be used in HTTP clients. I am here to argue that they are even more important when considering server-side applications.

At this point, we see that PSR-7 has been expanded to answer a second question: “How can we model HTTP messages for receiving a request, and sending back a response?” This is in addition to the original goal, but idea is the same: building a standard model of HTTP messages.

(For full disclosure, note that I became a sponsor on PSR-7 in December 2014, along with Beau Simensen as the coordinator.)

It is during MWOP’s tenure, before the successful acceptance vote in May 2015, that we see the PSR-7 interfaces expand in number, and become “immutable” (with one intentional exception, and other unintentional exceptions).

So we can see that the purpose of PSR-7 is to model 2 sets of HTTP messages using 7 interfaces: one set for when PHP sends a request and receives a response, and an addition set for when PHP receives a request and sends a response.

The Purpose of the Server(Request|Response) RFC

The proposed RFC starts out by asking a different question. It is not concerned with modeling HTTP messages, whether when sending or receiving them. Instead, it asks: “How can we take the request-related superglobals in PHP, and the various response-related global functions in PHP, and encapsulate them in objects, to make them at least a little more object-oriented?” Becuase the RFC begins with a different question, it leads to a different answer.

You end up with a ServerRequest object that exposes almost only properties, mimicking PHP’s superglobals. The properties are read-only, since they represent user input that should be copied out, not changed-in-place. As a convenience, a lot of common $_SERVER['HTTP_*'] values are parsed into more usable representations. Conceding the needs of application development, there are properties and methods for truly immutable values relating to application-specific parameters, parsed content input, and so on.

You also end up wih a ServerResponse object that exposes only methods, mimicking some of PHP’s global functions. Instead of emitting headers and cookies on each call to the related methods, it buffers and retains the header and cookie values until you decide to send them. As a collection point for those values, and for content, you can inspect the state of the object prior to sending, and modify it as needed. It has some convenience methods, not least of which includes sending content as a download, or as JSON, with the appropriate headers.

Conclusion

I hope this helps to clear up any confusion as to the purpose of the RFC, vs. the purpose of PSR-7. They start with different questions, and have different goals. I think it would be better to see them as orthogonal to each other at worst, and complementary at best.

Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.