As far as I can see, the essential difference between PSR-15 and your proposal is about the responsibility for dispatching the next middleware: 1. with your version: it is determined at *compile time*, by implementing the appropriate interface; thus the stack should be responsible for it only. 2. with the PSR-15 version: it is determined at *run time*, thus the stack and the middleware are responsible for dispatching the next middleware.
Django, StackPHP and Guzzle for example, have chosen an approach which seems to align better to your version. In essence, their middlewares could be typed as: (RequestInterface -> ResponseInterface) -> (RequestInterface -> ResponseInterface) Or, if we want to use PHP interfaces only, then we could type them: interface ExchangeInterface { public function __invoke(RequestInterface $request): ResponseInterface; } interface MiddlewareInterface { public function __invoke(ExchangeInterface $next): ExchangeInterface; } At first glance that could solve your issues with the current PSR-15, the *exchanger* does not seem to be responsible for dispatching the next exchanger and middlewares are simple exchange factories. And moreover we do not need middleware dispatchers anymore. Unfortunately that isn't very attractive in PHP, a middleware would look like: class UnicornMiddleware implements MiddlewareInterface { public function __invoke(ExchangeInterface $next): ExchangeInterface { return new class($next) implements ExchangeInterface { private $next; public function __construct($next) { $this->next = $next; } public function __invoke(RequestInterface $request): ResponseInterface { return (($this->next)($request))->withHeader('X-PoweredBy', 'Unicorns'); } }; } } That's probably one of the reasons why StackPHP uses `__construct` and Guzzle uses closures. But even worse, the inner ExchangeInterface instance is still responsible for dispatching the next middleware :( Are the PSR-15 interfaces so bad? From the perspective of a functional programmer, we can do some simple currying <https://en.wikipedia.org/wiki/Currying> to change the typing to get better interfaces: (RequestInterface -> ResponseInterface) -> (RequestInterface -> ResponseInterface) // using curry: (RequestInterface -> ResponseInterface) -> RequestInterface -> ResponseInterface // and again: ((RequestInterface -> ResponseInterface) -> RequestInterface) -> ResponseInterface Again, if we use PHP `interfaces` only, the last version could look like this in PHP: interface ExchangeInterface { public function __invoke(RequestInterface $request): ResponseInterface; } interface MiddlewareInterface { public function __invoke(ExchangeInterface $next, RequestInterface $request); } Aside from the parameter order, the similarities to the PSR-15 version are already obvious (Sadly, the names and implied contracts are very different and PSR-15 does not describe a functional middleware pattern anymore :cry: ). Anyway, the example above becomes much simpler with the current PSR-15 interfaces: class UnicornMiddleware implements ServerMiddlewareInterface { public function process(ServerRequestInterface $request, DelegateInterface $delegate) { return $delegate->process($request)->withHeader('X-PoweredBy', 'Unicorns'); } } Thus I believe your proposal does not fit better to the middleware pattern. -- 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+unsubscr...@googlegroups.com. To post to this group, send email to php-fig@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/b0794cd8-089a-4753-bbf5-9a3d0e833b06%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.