Sure. A warning though, wall of text follows.
Let's say that a HTTP request spec became part of PSR-3, and that the spec document says that HTTP requests MUST implement this API:
public function headers();
public function content();
// etc.
Now kriswallsmith decides to make his Buzz HTTP request match the spec. So he implements his version:
<?php
namespace Buzz\Message;
class Request
{
public function headers()
{
// ...
}
public function content()
{
// ...
}
// etc.
}
And Guzzle update their implementation to match the spec:
<?php
namespace Guzzle\HTTP\Message;
class Request
{
public function headers()
{
// ...
}
public function content()
{
// ...
}
// etc.
}
Great! Now there are two compliant implementations of PSR-3 HTTP requests.
Now I come along and want to write a component that does something with a PSR-3 standard HTTP request:
<?php
namespace Ezzatron;
class RequestHandler
{
public function handle(Request $request)
{
// etc.
}
}
But there's something missing here. I don't have a use statement yet. But which implementation do I use?
If I use Buzz\Message\Request I can't use Guzzle\HTTP\Message\Request and vice versa. The only way to accept any and all possible implementations is to drop the type hint and assume I'm getting a standard implementation:
<?php
namespace Ezzatron;
class RequestHandler
{
public function handle($request)
{
// let's hope I've got a standard request otherwise this will fail...
$content = $request->content();
}
}
The above is pretty undesirable. It's flaky and it's inconsistent with typical OO design.
So what's the better alternative? Obviously a common PHP interface. But an common interface must live somewhere outside the two projects.
So let's assume that FIG implements a HTTP message library which defines a common interface:
<?php
namespace FIG\HTTP\Message;
interface Request
{
/**
* @return array
*/
public function headers();
/**
* @return string
*/
public function content();
}
And let's also assume that Buzz and Guzzle mark their request implementations as implementing the above interface.
Now my component can be implemented in a nice, elegant way:
<?php
namespace Ezzatron;
use FIG\HTTP\Message\Request;
class RequestHandler
{
public function handle(Request $request)
{
// etc.
}
}
This makes a lot more sense. If implementers wish to participate in PSR-3 HTTP request compatibility, they simply bring in the FIG library as a dependency and implement the interface.
Now consider that another HTTP library comes on the scene, but in its HTTP request implementation, it does things a little differently. Maybe instead of a string for the request content, it provides an object that helps with consuming multipart MIME data:
<?php
namespace Some\Awesome\HTTP\Message;
use Some\Awesome\HTTP\Content\ContentInterface;
class Request
{
/**
* @return array
*/
public function headers()
{
// etc.
}
/**
* @return ContentInterface
*/
public function content()
{
// etc .
}
}
This new implementation arguably does a better job than any existing one, but because there is a standards document, rather than just being non-compatible, it gets the bad connotation of being 'non-standards-compliant'.
So let's review what the standardization provided versus the actual implementation.
The implementation of a standard interface:
- Allowed me to provide support for any HTTP request implementing the standard interface.
- Allowed developers to implement said interface for better interoperability.
- Allowed developers the freedom to choose to break compatibility in favour of an improved API.
The standard itself (without an implementation):
- Forced me to implement my component in a less than desirable way.
- Did not greatly improve interoperability.
- Stifled progression and created a negative stigma associated with a technically better but non-compliant implementation.
That is why I say that the HTTP request and things like it do not belong in specs, but in libraries; and that they are in fact detrimental.