Hi Rowan,

Again, thanks for your time and effort in evaluating this proposal.


> On Feb 18, 2020, at 14:21, Rowan Tommins <rowan.coll...@gmail.com> wrote:
> 
> - What's the sales pitch - what do YOU think is great about these classes?
> 
> ...
> 
> Sell it to me! :)

I don't do sales; occasionally I can present a good narrative. Maybe the 
narrative below will help.


> - When working out the details, what code should we be picturing using the 
> new classes?

Not to be flippant, but: request-reading and response-writing code?


>> ...a built-in OO-ish request/response object set...
> 
> "OO-ish" is a wise choice of words here. One of the reasons I'm not terribly 
> keen on this proposal - particularly the request half - is that I'm a bit of 
> an OO purist.

Heh -- yes, I am aware of the impurities (both perceived and actual) of 
ServerRequest. ;-)

However ...


> The lack of behaviour also makes it less useful to people writing their own 
> request and response objects: if I have a copy of $_POST and want to put it 
> in my own object property, why would I first pass it to a ServerRequest 
> object, and then get it straight back out again, if the object isn't helping 
> me do anything with that data?

... in this case, ServerRequest does quite a bit that is easy to take for 
granted, since it does so quickly and quietly. Among other things:

1. It "bundles" several related pieces of data; not just $_POST but $_GET, 
$_COOKIES, etc., so they can be carried around together.

2. It separates that data from global state.

3. It parses some of that data into commonly-needed structures (eg. the 
`$accept*` arrays).

4. Its copies of that data are read-only and immutable, so that once set they 
cannot be modified at a distance when shared around; this keeps them stable 
throughout the system.

So while it is true that ServerRequest "lacks behavior" in the sense that it 
doesn't "do" anything *after* construction, but it also true that it does quite 
a bit *at* construction.

Indeed, the vast majority of uses (in practice) for a ServerRequest type of 
object are "reading" or "getter" uses. There is comparatively little need to 
write to a ServerRequest instance. Almost all of the time, all you need is to 
read from it post-construction.

Further, there's no need to optimize for calculation-on-demand, since the 
calculations are so speedy in the first place. And since it will happen only 
once in the request lifespan, you might as well build all the properties at 
construction-time. At that point, getter-type methods are just returning what 
has already been calculated. And at *that* point, read-only properties do the 
trick quite nicely.

For the comparatively-rare (but still necessary) times when you need to write 
to a ServerRequest type of object, it is open to extension in userland for 
those application-specific cases.


>> ...that does pretty much just what PHP itself already does...
> 
> As you say elsewhere, this is useful for helping people migrate to it. The 
> flipside of that is that it ties us into past decisions, rather than 
> evaluating whether those decisions are still what we want.

Your comment jogged my memory of an older conversation, 
<https://externals.io/message/100087>, in which you figure prominently, and in 
which I pointed out the existence of the prior version of this RFC. Many things 
there are reminiscent here:

- Should superglobals be made read-only?
- Should superglobals be made into objects instead of arrays?
- Should superglobals be replaced entirely with some new system?
- Are additional superglobals needed?
- Should there be a layer of indirection between superglobals and their use in 
applications?

This RFC answers from (if you'll pardon the word) a conservative position: no, 
no, no, maybe, and yes. In the last case, this RFC can be construed to provide 
ServerRequest as that layer of indirection for some of the superglobals.


> The approach in providing both $files and $uploads arrays is a good 
> compromise - provide the new better way, but also an easy-to-migrate way. I'd 
> love to see them named more distinctly, though, maybe even calling one of 
> them "legacy". I'd probably also make them methods so that the data can be 
> stored once (in the new format) and re-formatted on demand (again, objects as 
> behaviour rather than data).

I appreciate that concession on your part, and thanks for saying.

I think $uploads is a pretty distinct name, while being clearly related to 
files. And, as I mentioned earlier, the cost of reformatting the $_FILES 
structure to $uploads is so low that it might as well occur at construction 
time, instead of adding a method to calculate-and-retain the reformatted 
structure.


>> ...easing their transition away from global state
> 
> This I find less convincing. To quote from further down the e-mail, I wrote:
> 
>>> ...you can do almost as much in that direction as the RFC by writing 
>>> "$get=$_GET; unset($_GET);" The hard problem is that the entry point for a 
>>> request is in global scope, not a main() or handleRequest() function.
> 
> and you replied:
> 
>> Another "hard" problem is carrying those values around in the system once 
>> they are decoupled from global state; the objects in this RFC purport to do 
>> so.
> 
> If all the object does is "carry around" a copy of the superglobal arrays, I 
> can write it in about a dozen lines of code.

I answered this above, but to reiterate: "carrying around" is *one* thing 
ServerRequest does, but not *all* it does.


> Again, the response object is more powerful in this regard, because we can't 
> currently pass around a list of prepared cookies and trivially output it to 
> the client.
> 
> Along the lines of my previous message about decoupling concerns, I would 
> personally like the response parts of the proposal split out and re-cast as a 
> kind of "response buffer".

I admit I considered this. However, it makes more sense to me in terms of 
symmetry/complementarity, and in terms of "what we need on a daily basis", to 
provide both the request object and the response object together.


>> I had considered mentioning the dual OO+procedural APIs of mysqli, date, 
>> etc. but it seemed too much in an already-long RFC; I'm glad you brought it 
>> up, as I did have it in mind.
> 
> This is an interesting comparison to consider. Just as those extensions have 
> procedural options for people who can't stand objects, the current proposal 
> has objects for people who like "OO-ish".

Yes, I think so too.


>>> Introducing these objects as part of a new calling convention for PHP 
>>> scripts would definitely add value, and make them a true replacement for 
>>> the superglobals, but that would be a very different RFC.
>> 
>> That does seem rather ambitious. If you feel that's a valuable thing to add 
>> to PHP, perhaps it could be part of a future RFC, maybe even one that uses 
>> the objects in this RFC as a starting point.
> 
> One of the things I don't like about the current proposal is that it's 
> modelled so closely around the current superglobals that I fear it would 
> actually be *harder* to replace them.

Maybe? I can similarly imagine that if new-and-different superglobals appear, 
the ServerRequest object can evolve to contain and/or translate between them.


> Parsing a request body from an arbitrary source into arrays that match the 
> structure of $_POST and $_FILES would be a really useful feature.

Yes, although one can do at least the $_POST portion with ServerRequest as it 
is now. For example, a naive userland factory might do this:

    class ServerRequestFactory
    {
        public function new(array $globals, ?string $content = null) : 
ServerRequest
        {
            if ($this->isJson($globals['_SERVER']['CONTENT_TYPE'] ?? '') {
                $globals['_POST'] = json_decode(
                    $content ?? file_get_contents('php://input'),
                    true
                );
            }

            return new ServerRequest($globals, $content);
        }

        protected function isJson(string $contentType) : bool
        {
            return $contentType === 'application/json'
                || substr($contentType, -5) === '+json';
        }
    }

Call `$request = (new ServerRequestFactory())->new();` and voila: the 
equivalent of `$_POST`, populated from JSON content, stored as $request->input.


> I also really want to see the day when I never have to interact with $_SERVER 
> again. Other than renaming it, this object's design makes that less likely, 
> not more.
> 
> Imagine if in future we're able to redesign the internals so that there is a 
> dedicated and reliable field for the requested URL; the current object 
> doesn't have anywhere we can put that. If we add it later, it will be too 
> late, code will be written that passes around ServerRequest objects, but 
> relies on the full array of CGI variables to reconstruct the URL.
> 
> If this object took a more opinionated view of what behaviour to encapsulate, 
> we could simply hide the "server" array completely. Common use cases would be 
> exposed via methods, and rarer use cases would have to be added in userland 
> with their own copy of $_SERVER. Then my dream of deprecating $_SERVER could 
> mean something other than moving it into an object.

Yes, the internals thread I pointed to earlier makes that clear.  And though I 
understand where you're coming from, especially regarding "a dedicated and 
reliable field for the requested URL", this RFC does not have that kind of 
ambition, nor do I expect it to in the future.

This proposal is satisfied to take only a smaller series of steps to ease a 
more limited set of problems, rather than revise major and wide-ranging 
elements of PHP overall. I presume you will find that unsatisfactory, but, 
well, there it is.


-- 
Paul M. Jones
pmjo...@pmjones.io
http://paul-m-jones.com

Modernizing Legacy Applications in PHP
https://leanpub.com/mlaphp

Solving the N+1 Problem in PHP
https://leanpub.com/sn1php

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to