Rework the Phalcon HTTP stack

I would like to rework the Phalcon HTTP stack, particularly the Request object and its lifecycle.

A while ago I was working on the HTTP authorization issue and turned attention to the fact that by every request of a HTTP header or a variable from $_SERVER the Request object scan the $_SERVER for the value.

Technically, the actual implementation allows to get the value from $_SERVER and to overwrite it at once bypassing the Request object. In fact, I don't think it is right. And there are the reasons of this:

  • The Request object doesn't keep its state, and actually the fact that it isn't static doesn't help much
  • Any part of the application can quite legally break the request encapsulation just by overwriting $_SERVER
  • We don't use local (static) cache by receiving values from $_SERVER, $_REQUEST and so on, and it has its impact on the performance
  • Each time, receiving a HTTP header, we convert HTTP-KEY to HTTP_KEY
  • But by receiving a key from $_SERVER we don't do the action described in the previous item
  • At the moment we don't have methods for receiving raw, untreated keys as well as keys that are ready for the search
  • Our ways of work with HTTP headers and other keys from $_SERVER can be different by receiving all keys or one key. This means, we receive keys of one type for get all, but use other keys for get one, so the user could face difficulties, because the techniques of receiving certain values are not predictable
  • The user has no possibility to receive a default value if the requested key is absent

On top of everything else I would like to work with the request headers separately. At the moment, I see the Request object as a composite object which includes such objects as Server, Headers, and Files. Of course, I'd like to substitute mocks for those objects at the stage of testing, or to allow outside developers to create their own extended versions of those objects, which implement the common interface.

If you look at $_SERVER, $_REQUEST and $_FILES attentively, it will be clear for you that these are only collections. Such realization brings about the understanding how the interfaces can be developed, for example, for such classes as Server, Headers and Files. But in fact it causes other questions, too...

For example, if these collections are immutable. On the one hand, it seems that Request must always be read-only, it reflects its nature. But the current implementation of a HTTP stack, for example, allows to change it in any place of the call stack with ease. Is this right? I'd like to discuss this question.

On the other hand, we'd like to append HTTP headers to a Request (by using Middlewares), or set the current HTTP method implicitly.

I think, we could do the bigger part of this work in any 3.x branch, keeping backward compatibility, just by declaring some methods deprecated and deleting them in the 4.x branch. In general, I'd like to know the community's opinion as to the questions raised above.

We don't use local (static) cache by receiving values from $_SERVER, $_REQUEST and so on, and it has its impact on the performance

Can you elaborate on that?

I'm all in for encapsulable requests. Working with web-sockets, it could be really useful to swap request objects at run-time without any hacking... And the fact that Phalcon's classes are not decoupled from globals like SERVER,GET,POST are against roboustness.

For example:

namespace Phalcon\Http;

class Request implements RequestInterface, InjectionAwareInterface
{
    // ...

    protected _method;

    public final function getMethod() -> string
    {
        if !this->_method {
            // ...
        }

        return this->_method;
    }
}

We don't use local (static) cache by receiving values from $_SERVER, $_REQUEST and so on, and it has its impact on the performance

Can you elaborate on that?