PSR-7: why do Streams belong to this PSR?

208 views
Skip to first unread message

Rasmus Schultz

unread,
Sep 24, 2016, 9:29:55 AM9/24/16
to PHP Framework Interoperability Group
Hey FIG,

This week, I found myself doing some work with native PHP stream resources.

This particular work had no relation to HTTP at all, but to SMTP as it happens.

While writing this project, I thought, I should abstract streams behind an interface.

Of course, then it occurred to me, PSR-7 includes a stream-abstraction.

However, PSR-7 is primarily for HTTP Messages - it seemed wrong to depend on an HTTP abstraction just for the stream-abstraction, so I ended up not doing that.

In the end, I went with plain PHP stream resources, for two reasons - primarily because I didn't want to depend on an HTTP abstraction for streams, and also because the stream-abstraction of PSR-7 doesn't cover stream-filters, which I needed for this project.

Which brings me to my question: why was the stream-abstraction rolled in with the HTTP abstraction? (I did not find this question/answer in the PSR-7 meta.)

It seems like a stream-abstraction is a completely general thing - it's not specific to HTTP concerns at all; PHP streams are used for plenty of other things, and this abstraction could perfectly well stand alone without the HTTP abstraction, or not?

A stream-abstraction seems like it's more naturally a dependency of an HTTP abstraction - rather than belonging to it.

Is there a rational reason why two seemingly unrelated abstractions were put into a single PSR?

How would you feel about having a separate PSR for streams? And possibly extending the scope to also include a stream-filter abstraction?

Thanks,
  Rasmus

Daniel Hunsaker

unread,
Sep 24, 2016, 6:17:04 PM9/24/16
to PHP Framework Interoperability Group
On Saturday, September 24, 2016 at 7:29:55 AM UTC-6, Rasmus Schultz wrote:
Hey FIG,

This week, I found myself doing some work with native PHP stream resources. This particular work had no relation to HTTP at all, but to SMTP as it happens. While writing this project, I thought, I should abstract streams behind an interface. Of course, then it occurred to me, PSR-7 includes a stream-abstraction. However, PSR-7 is primarily for HTTP Messages - it seemed wrong to depend on an HTTP abstraction just for the stream-abstraction, so I ended up not doing that. In the end, I went with plain PHP stream resources, for two reasons - primarily because I didn't want to depend on an HTTP abstraction for streams, and also because the stream-abstraction of PSR-7 doesn't cover stream-filters, which I needed for this project.

Which brings me to my question: why was the stream-abstraction rolled in with the HTTP abstraction? (I did not find this question/answer in the PSR-7 meta.) It seems like a stream-abstraction is a completely general thing - it's not specific to HTTP concerns at all; PHP streams are used for plenty of other things, and this abstraction could perfectly well stand alone without the HTTP abstraction, or not? A stream-abstraction seems like it's more naturally a dependency of an HTTP abstraction - rather than belonging to it. Is there a rational reason why two seemingly unrelated abstractions were put into a single PSR?

My guess (I wasn't involved in the process on this one) is that the stream abstraction was considered useful, and no other PSR was already covering it at the time. While splitting that into its own PSR makes sense, the added complexities of developing a second PSR, especially when the current one relies on its content, would likely have been seen as an unnecessary complication for the current PSR itself - that is, PSR-7 would likely still be unapproved, waiting on the Streams PSR to be finalized, first, along with all the unforeseen complications it would have along the way. Ultimately the right approach? Hard to say, but looking back provides a much different view than looking forward.
 
How would you feel about having a separate PSR for streams? And possibly extending the scope to also include a stream-filter abstraction?

For my part, a full-blown Streams PSR makes sense. Especially if it can be made to expand the stream interface in PSR-7, such that compatible implementations could be used there as well. Not necessarily *extending* it, per se, though I suppose that would probably also be a good idea for continued compatibility between the PSRs. Especially since PSRs can't really be revised once approved.

Of course, I'm not a voting member, so this is just my 2¢...
 
Thanks,
  Rasmus

- Dan 

Larry Garfield

unread,
Sep 25, 2016, 1:48:17 AM9/25/16
to php...@googlegroups.com
On 09/24/2016 11:17 PM, Daniel Hunsaker wrote:
On Saturday, September 24, 2016 at 7:29:55 AM UTC-6, Rasmus Schultz wrote:
Hey FIG,

This week, I found myself doing some work with native PHP stream resources. This particular work had no relation to HTTP at all, but to SMTP as it happens. While writing this project, I thought, I should abstract streams behind an interface. Of course, then it occurred to me, PSR-7 includes a stream-abstraction. However, PSR-7 is primarily for HTTP Messages - it seemed wrong to depend on an HTTP abstraction just for the stream-abstraction, so I ended up not doing that. In the end, I went with plain PHP stream resources, for two reasons - primarily because I didn't want to depend on an HTTP abstraction for streams, and also because the stream-abstraction of PSR-7 doesn't cover stream-filters, which I needed for this project.

Which brings me to my question: why was the stream-abstraction rolled in with the HTTP abstraction? (I did not find this question/answer in the PSR-7 meta.) It seems like a stream-abstraction is a completely general thing - it's not specific to HTTP concerns at all; PHP streams are used for plenty of other things, and this abstraction could perfectly well stand alone without the HTTP abstraction, or not? A stream-abstraction seems like it's more naturally a dependency of an HTTP abstraction - rather than belonging to it. Is there a rational reason why two seemingly unrelated abstractions were put into a single PSR?

My guess (I wasn't involved in the process on this one) is that the stream abstraction was considered useful, and no other PSR was already covering it at the time. While splitting that into its own PSR makes sense, the added complexities of developing a second PSR, especially when the current one relies on its content, would likely have been seen as an unnecessary complication for the current PSR itself - that is, PSR-7 would likely still be unapproved, waiting on the Streams PSR to be finalized, first, along with all the unforeseen complications it would have along the way. Ultimately the right approach? Hard to say, but looking back provides a much different view than looking forward.

From what I recall, that is a fairly accurate summary.  The same applies to UriInterface, which is technically useful outside of HTTP messages but trying to factor that out was just more work than anyone had the stomach for.


How would you feel about having a separate PSR for streams? And possibly extending the scope to also include a stream-filter abstraction?

For my part, a full-blown Streams PSR makes sense. Especially if it can be made to expand the stream interface in PSR-7, such that compatible implementations could be used there as well. Not necessarily *extending* it, per se, though I suppose that would probably also be a good idea for continued compatibility between the PSRs. Especially since PSRs can't really be revised once approved.

Of course, I'm not a voting member, so this is just my 2¢...

I would much rather see PHP's native stream interfaces improved to not suck, rendering a user-space wrapper of them unnecessary.  If wishes were horses... :-)

--Larry Garfield

Rasmus Schultz

unread,
Sep 25, 2016, 1:35:44 PM9/25/16
to php...@googlegroups.com
Why would it be more work to do, for example, a URI abstraction first,
as a separate PSR?

By my calculations, getting people to agree about smaller, isolated
abstractions should be a lot easier than getting people to agree on a
larger, combined package of abstractions.

You had to do the same work regardless, write the same specifications, etc.

Does the process itself really create that much overhead?

I mean, I know it's a lot of work - I'm involved in the HTTP factory
and HTTP middleware proposals right now, and it has been far more work
than I had ever anticipated.

Anyhow, the main reason I brought it up is, can we fix it? Or is it
simply too late?

Simply splitting the PSR and packages doesn't seem like an option,
since unfortunately the package is namespaced as Psr\Http\Message, and
URIs do not belong to the message sub-domain at all - likewise,
Streams do not even belong to the HTTP sub-domain.

One way to address this, maybe, would be to simply duplicate the
interfaces, e.g. so that a class could implement both, say,
Psr\Http\Message\StreamInterface and Psr\StreamInterface.

The more correct solution would be a 2.0 release of PSR-7 that depends
on two new PSRs. Client code would need to upgrade by replacing, for
example, references to Psr\Http\Message\StreamInterface with
Psr\StreamInterface, etc.

But is there any kind of policy about PSR versioning? Is a 2.0 of an
existing, approved PSR even a thing, or are they finite and set in
stone forever?

Or how does that work?
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/php-fig/cLfsPZQVTuA/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/fd07b8eb-4194-fa4f-9a89-f71bf54aa520%40garfieldtech.com.
>
> For more options, visit https://groups.google.com/d/optout.

Daniel Plainview

unread,
Sep 25, 2016, 4:16:36 PM9/25/16
to PHP Framework Interoperability Group
> By my calculations, getting people to agree about smaller, isolated 
abstractions should be a lot easier than getting people to agree on a 
larger, combined package of abstractions. 

You state that general-purpose URI is "smaller, isolated abstraction". 
However, in general case, you have to think about use cases more carefully. Sometimes, it is just really hard work.
It is much harder to find consensus, etc.

On other hand, it's easier to work within specific domain.
You introduce only methods that make sense for this domain. 
It increases cohesion of the package.

I understand your point, but it's not terrible to have the same concept in different domains, especially if it behaves slightly differently.
There are a lot of possible variations of the URI I think.
Sometimes you need highly-detailed URI (like $uri->getQuery()->getParam('foo', 'default')), sometimes you are OK with $uri->getQuery(): string.
Sometimes you want to limit possible URIs for specific domain (I don't think it makes sense to allow ftp:// URIs for PSR-7, for example).
Sometimes you want to reduce API of the class, because some parts of it doesn't make much sense in some domain.

Every abstraction has a price. Sometimes you don't want to pay it and choose clarity of intent.

Matthew Weier O'Phinney

unread,
Sep 26, 2016, 10:27:16 AM9/26/16
to php...@googlegroups.com
On Sun, Sep 25, 2016 at 12:35 PM, Rasmus Schultz <ras...@mindplay.dk> wrote:
> Why would it be more work to do, for example, a URI abstraction first,
> as a separate PSR?
>
> By my calculations, getting people to agree about smaller, isolated
> abstractions should be a lot easier than getting people to agree on a
> larger, combined package of abstractions.
>
> You had to do the same work regardless, write the same specifications, etc.
>
> Does the process itself really create that much overhead?

Yes, it does, particularly at the point at which splitting them off to
their own PSRs was proposed; we were already *years* into discussions
on PSR-7 when the UriInterface was proposed, and it wasn't until the
stream interface was fully fleshed out that folks started talking
about splitting it off to its own proposal.

Both the stream and URI interfaces were requirements for PSR-7, and
moving them into their own proposals was going to necessitate at least
2 months apiece before we could move forward on PSR-7; realistically,
we were looking at something more like 6-9 months, and very likely
longer.

Why?

Because if we split them off, the scope would have grown for each.

With PSR-7, we could focus on the specific needs for HTTP usage.
Generic interfaces for streams and URIs would have expanded scope
considerably:

- With PSR-7, we could focus only on validity of HTTP/S URIs, and not
need to worry about the fact that URIs vary structure based on scheme
(e.g., data URIs do not require an authority). A generic URI interface
would have to account for far more than we did in PSR-7.
- With streams, we inevitably would have needed to work on async
features to allow async stream processing, which would likely mean
needing a PSR on promises in place as well. Additionally, we likely
would have started looking at how to facilitate things like
generators, callbacks, etc. as stream sources. (These can already be
accommodated in PSR-7, but only in implementing libraries, not
specifically as part of the specification.)

Considering the amount of time we'd already spent (years), and the
fact that we were getting consensus around all other aspects, we
decided to include these interfaces as part of the specification, as
they were specific to the domain we were covering. We also noted that
each of these would be suitable for their own specifications, and,
should those specifications be completed, we could propose a new
specification that evolves PSR-7 to use those.

<snip>

> Anyhow, the main reason I brought it up is, can we fix it? Or is it
> simply too late?

See above; we can create new PSRs covering those topics
(interestingly, those parties who seemed most keen on doing so when
discussing PSR-7 have not yet proposed them!), and then do a new PSR
that would replace PSR-7 (much as PSR-4 replaces PSR-0, and PSR-12
will replace PSR-1/PSR-2).

<snip>

> The more correct solution would be a 2.0 release of PSR-7 that depends
> on two new PSRs. Client code would need to upgrade by replacing, for
> example, references to Psr\Http\Message\StreamInterface with
> Psr\StreamInterface, etc.
>
> But is there any kind of policy about PSR versioning? Is a 2.0 of an
> existing, approved PSR even a thing, or are they finite and set in
> stone forever?
>
> Or how does that work?

See above. Once a PSR is accepted, it cannot change. New PSRs may,
however, replace them. You can see a similar process in the IETF:

- RFC 7230 obsoletes RFC 2616
- RFC 2822 obsoletes RFC 822

The same process is followed in FIG.
> You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/CADqTB_i-ovk2cnrs6mqT%3DBwmJ4mfxdT%3DcZHc-J1_PhLtgXBM4g%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.



--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Rasmus Schultz

unread,
Sep 26, 2016, 12:09:51 PM9/26/16
to php...@googlegroups.com

That answers everything plus a few questions I hadn't even pondered - thanks, Matthew :-)



>> To post to this group, send email to php...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/php-fig/fd07b8eb-4194-fa4f-9a89-f71bf54aa520%40garfieldtech.com.
>>
>> For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

> To post to this group, send email to php...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/CADqTB_i-ovk2cnrs6mqT%3DBwmJ4mfxdT%3DcZHc-J1_PhLtgXBM4g%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.



--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/cLfsPZQVTuA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages