Closed oscarotero closed 8 years ago
You have a dedicated ClientDispatcher
.
I'm afraid this illustrates the problem I've been been trying to explain - because our interface relationships aren't symmetric with those of PSR-7: ServerMiddlewareInterface
is not a specialization of MiddlewareInterface
, but ServerRequestInterface
is a specialization of RequestInterface
.
It's not a natural fit for the concepts defined by PSR-7 at all: there's no such thing as a "client request" - the two types are not supposed to be mutually exclusive, and a "server request" is supposed to be interchangible with a "generic request".
I remain convinced that the way we're modeling this is wrong.
Yes, but there's a big difference: In PSR-7 ServerRequestInterface
extends RequestInterface
adding more methods, not overriding them.
Php does not allow to extend an interface to change the signature of a method defined previously. So, if you have the method process(RequestInterface $request, DelegateInterface $next)
and override it with process(ServerRequestInterface $request, DelegateInterface $next)
returns a fatal error. This is why two different interfaces are needed. I remember some different approaches discussed to handle this:
MiddlewareInterface
that is extended by ClientMiddlewareInterface
and ServerClientInterface
(I'm not a fan of empty interfaces)RequestInterface
and throw an exception if the middleware need a ServerRequestInterface
but RequestInterface
is provided.MiddlewareInterface
adding a new method, instead override it. For example: processRequest()
and processServerRequest()
.My favorite solution is the second, but I know that is not full typed as the others.
Php does not allow to extend an interface to change the signature of a method defined previously
Well aware of that, yes. The problem is, the type relationship is generic, and there is no way to describe a generic type relationship in PHP at present, not even with a php-doc block. (at least not officially, although etsy/phan
is attempting something experimental in that direction.)
The bottom line is that this type relationship cannot be described by the PHP type system.
Attempting to achieve type safety by creating an incorrect type relationship (and by "incorrect", I mean "directly conflicting with PSR-7") does not make for a sound proposal, and doesn't actually achieve full type-safety anyhow, static or run-time.
My favorite solution is the second, but I know that is not full typed as the others
I agree, and I think we have to accept reality for what it is.
In my opinion, the only other acceptable model, is the one interface plus a second identical interface, essentially a marker/tag interface, e.g.:
interface MiddlewareInterface {
public function process(RequestInterface $request, DelegateInterface $delegate);
}
interface ServerMiddlewareInterface extends MiddlewareInterface {
}
While this does not provide type-safety for server-middleware, at least it correctly mirrors the type-relationships in PSR-7, creating symmetry, such that:
var_dump($server_middleware instanceof ServerMiddlewareInterface); // TRUE
var_dump($server_middleware instanceof MiddlewareInterface); // TRUE
Contrast that with what we're proposing currently, which means that:
var_dump($server_middleware instanceof ServerMiddlewareInterface); // TRUE
var_dump($server_middleware instanceof MiddlewareInterface); // FALSE (!)
This makes no sense in the light of PSR-7, where:
var_dump($server_request instanceof ServerRequestInterface); // TRUE
var_dump($server_request instanceof RequestInterface); // TRUE
At least in this case, the type-relationship is symmetrical with PSR-7 - it just isn't strict enough, but that's impossible given the constraints of the type-system.
At least, the existence of ServerRequestInterface
in this case serves to identify middleware, to developers, as requiring a server request, and, assuming developers use it correctly, does provide the benefit in middleware stacks of being able to distinguish middleware tagged as requiring a server request.
Given that this provides no type safety, I would also settle for a single interface - while a single interface doesn't really create symmetry, at least it doesn't directly conflict with the PSR-7 type-model.
I like this model. Is true that does not provide true type safety but the middleware could throw a InvalidArgumentException
. The single interface model (my favorite solution) was discarted early in the fig mailing list, and this one suggested by you is similar but a bit better typed. This solution reduce my implementation in just one dispatcher class, and that would be amazing.
I am fine with ServerMiddlewareInterface extends MiddlewareInterface
and no type check. To use native type checking, it does require that:
class FooMiddleware extends ServerMiddlewareInterface
{
public function process(RequestInterface $request, DelegateInterface $delegate)
{
$action = $this->getDispatchedAction($request);
// ...
}
private function getDispatchedAction(ServerRequestInterface $request)
{
return $request->getAttribute('dispatch.action');
}
}
This is what we have been doing without formal interfaces and it seems to work out fine. Can trip users up though.
Hello. Just want to drop here a middleware dispatcher implementation of this interface that I've created here: https://github.com/middleland/dispatcher As you can see, it's a minimal implementation allowing to use the dispatcher as a middleware, as showed in the examples.
I really like the interface and love to see something similar in the final psr version.