PSR-7 Objects Could Be Immutable

I’ve been thinking a lot about immutable objects lately. Yegor Bugayenko claims that Objects Should Be Immutable and PSR-7: HTTP message interfaces are designed to be immutable.

Messages are values where the identity is the aggregate of all parts of the message; a change to any aspect of the message is essentially a new message. This is the very definition of a value object. The practice by which changes result in a new instance is termed immutability and is a feature designed to ensure the integrity of a given value.

There has been some discussion around the mutability of streams in PSR-7.

Andrew Carter wrote a post discussing why PSR-7 Objects Are Not Immutable saying:

You shouldn’t expect to see the message that was written to the response actually rendered. The code we have written explicitly avoided returning the response by throwing the exception. However, if you disable the Whoops error handler and use the default templated error handler you will find that your message still appears at the top of the error page that is generated by the framework.

Paul M. Jones mentions the immutability of streams in Avoiding Quasi-Immutable Objects in PHP.

If a stream or similar resource has been opened in a writable (or appendable) mode, and is used as an immutable property, it should be obvious that object immutability is not preserved.

This makes sense. If you write to a stream, then rewind it and write it, the value has changed.

I don’t think this makes the class wrapping the stream mutable.

Yegor talks about this idea in Gradients of Immutability.

His argument would be that the object isn’t a constant, but it is immutable.

The object isn’t representative of the content of the stream, but of the reference to the stream.

It’s like if you had an object that interacted with a file.

You might argue that a File object isn’t immutable because if it was $f->read() should have returned “hoopla”. But I disagree.

The File object is wrapping a file name, a pointer to a file in the file system. The object isn’t constant, but it is immutable because it’s data is the file name and not the contents of the file.

I’d be breaking immutability if I added a setFilename method that allowed you to change what file the object was pointing to.

Zend Diactoros

The PSR-7 implementation that I typically use is Zend Diactoros because it’s what used by Radar.

I was hoping to dig in and show how it actually is immutable, but I can’t. Because it isn’t. 🙁

It could have been, but the Stream::attach method makes it mutable.

The strange thing is that it implements Psr\Http\Message\StreamInterface which does not define an attach method.

So Zend\Diactoros\Stream chooses to define additional methods that are not part of the PSR-7 interface, and in doing so, breaks immutability.

Guzzle PSR-7

Looking at other implementations, it would appear Guzzle PSR-7 streams are immutable.

Author: Andrew Shell

Madison, WI developer, Co-Founder and CTO of Pinpoint Software, founder of Madison PHP.

7 thoughts on “PSR-7 Objects Could Be Immutable”

  1. I assert that the streams are not the only contestant for the “immutable or not?” question.

    For example, ServerRequest::withParam() opens the door to mutability as well. If you pass an object as the param value, that object remains mutable. Anything can change the values on that object, and when you retrieve it again from the ServerRequest its values may have changed.

    Alternatively, if you pass an array for the param value, and one of the array elements contains an object, you have the same problem.

    1. I agree there are other areas besides streams that could break immutability. One question I’d be curious of your opinion on. In Yegor’s post under Encapsulated Mutability he shows having a final StringBuffer property which is mutable, but he considers the encapsulating class immutable.

      Would passing an object as reference through withParam actually still be immutable because the encapsulating object is holding an immutable reference to a memory location? It’s fuzzy in PHP because we’re not directly working with memory pointers. I could see the argument either way.

      1. Would passing an object as reference through withParam actually still be immutable because the encapsulating object is holding an immutable reference to a memory location? It’s fuzzy in PHP because we’re not directly working with memory pointers. I could see the argument either way.

        I think the answer is “no.” AFAICT, the expectation when using the word “immutable” is not “the underlying memory pointer is the same.” It is, “the underlying value is not going to change.” Cf. this comment at Yegor’s:

        http://www.yegor256.com/2016/09/07/gradients-of-immutability.html#comment-2910095899

        1. I’d agree. Because like the comment mentioned, how is a StringBuffer any different than just a String that is changed. Thanks for taking the time to comment Paul. I find that Yegor’s ideas are thought provoking but a bit extreme at times.

  2. If you’re obsessed with immutability, it should be fairly easy to write a read-only stream decorator? Of course that’s no guarantee exactly – at the end of the day, all state is mutable in PHP, modeling immutability is merely a design choice, not something the language was designed to enforce.

Leave a Reply