How Many PSR-7 Implementations Exist?

More specifically, how many implementations of PSR-7 ServerRequestInterface exist?

Initially, it appears the answer might be as many as three dozen.

But increasingly it looks like the real answer, to a first approximation, is “zero.”

To implement ServerRequestInterface, the methods withAttribute() and withParsedBody() MUST maintain the immutability of the message object. However, none of the existing implementations do that.

To see for yourself, clone my PSR-7 Immutability Testing repository and run the tests, which cover the three most popular PSR-7 implementations.

Immutability is very difficult to implement – at least, not without some serious restrictions, none of which are specified by PSR-7 ServerRequestInterface.The more I work with it, the more I begin to think that it is not fully implementable-as-specified in the first place.

UPDATE: Apparently I was on to something when I suggested that PSR-7 cannot be implemented as written. Sara Golemon (who has forgotten more about PHP internals than I will ever know) points out, “It is not technically implementable. And thus you’re technically correct, the best kind of correct.” (Archived for posterity at https://archive.is/BnkGb .)

UPDATE 2: Reddit commenters point out that the ServerRequestInterface::getAttributes() method states “Attributes will be application and request specific, and CAN be mutable.” This seems at odds with the withAttribute() method, which requires that the object remain immutable. At the best, this seems like an oversight in the spec, and at the worst it is an internal contradiction.

Are you stuck with a legacy PHP application? You might like my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.
Share This!Share on Google+Share on FacebookTweet about this on TwitterShare on RedditShare on LinkedIn

5 thoughts on “How Many PSR-7 Implementations Exist?

  1. Perhaps PSR interfaces should come with some tests to help prevent cases such as this.

    I implemented a PSR-6 (cache) library, and I’m sure I’ve missed immutability somewhere, especially since immutability is a rather uncommon thing in PHP.

    • > Perhaps PSR interfaces should come with some tests to help prevent cases such as this.

      I think there’s a bigger problem. It’s starting to appear (to me anyway) that those ServerRequestInterface methods *cannot be implemented as specified*.

  2. You’re incorrectly claiming the implementations of the interface are “incorrect”, when, in point of fact, you’re not manipulating the message instances, *but an instance of some other object entirely that you’re composing into the message*. The message instance is not being mutated, the instance you’re composing into it is.

    I suspect you’ll argue that this is semantically the same as the composing object being mutable. I would argue that is only the case if the particular methods were part of the original message _representation_; i.e., if changing an object value within them would result in a different HTTP message. In both cases you quote, withAttribute() and withParsedBody(), that is not true; these are meant to be values *computed* from the message itself.

    Immutability was added to PSR-7 in large part because the HTTP specification indicates a change in any member of the message representation, which includes the request/status lines, headers, and message body, results in a new message. Thus, any members that do so within the spec must be immutable. (We had to make one exception to that rule with regards to streams, as there is no way in userland to even mimic immutability in a PHP stream resource, other than declaring it read-only; even then, changes in cursor position can lead to problems. Since manipulating the stream requires making a conscious decision to do things such as write() or seek(), these are easy to spot and correct within userland code.)

    Which brings me back to my point: you’re not testing the immutability of the messages. You’re testing the immutability of calculated products.

    The specification does not go into whether those calculated values injected into new instances should be immutable or not. I think that would be fairly far reaching.

    There are ways for PSR-7 implementations to also enforce immutability in these, however, if really desired: they could try and detect objects coming in, and clone them when assigning them to the new instance they create. I considered this for Diactoros, but felt (a) this would be unexpected behavior for most consumers, and (b) might have detrimental performance implications (due to language considerations), and/or (c) could lead to some problems when circular dependencies are encountered. I honestly feel it’s unnecessary, and not something to address until the language itself has some sort of support for immutable objects

    • You’re incorrectly claiming the implementations of the interface are “incorrect”, when, in point of fact, you’re not manipulating the message instances, *but an instance of some other object entirely that you’re composing into the message*. The message instance is not being mutated, the instance you’re composing into it is.

      This strikes me as being at odds with StreamInterface being defined as mutable. Quoting the spec:

      Unlike the request and response interfaces, StreamInterface does not model immutability. In situations where an actual PHP stream is wrapped, immutability is impossible to enforce, as any code that interacts with the resource can potentially change its state (including cursor position, contents, and more). Our recommendation is that implementations use read-only streams for server-side requests and client-side responses. Consumers should be aware of the fact that the stream instance may be mutable, and, as such, could alter the state of the message; when in doubt, create a new stream instance and attach it to a message to enforce state.

      So, when one manipulates the underlying resource, one isn’t manipulating the StreamInterface instance itself, just the underlying resource. Which means StreamInterface is … immutable? Or not?

  3. […] the HTTP specification indicates a change in any member of the message representation […] results in a new message […]
    Where in the HTTP RFC’s can I find this statement?

Leave a Reply

Your email address will not be published. Required fields are marked *