zendframework / zend-stratigility

Middleware for PHP built on top of PSR-7 and PSR-15
BSD 3-Clause "New" or "Revised" License
235 stars 57 forks source link

Middleware Pipe marked as final #181

Closed ghost closed 5 years ago

ghost commented 5 years ago

In order to efficiently use dependency injection, I need to be able to use multiple MiddlewarePipes; specifically one for the core middleware pipeline, and one for the route specific middleware pipeline.

With a final class this is a real challenge as my DI can return a new instance each time or a shared instance, depending on how I configure it. Neither is workable.

If I were able to extend the class with CoreMiddleware and RouteMiddleware it would be fine, and work as expected.

What was the reasoning to make the class final, as in v2 it worked as expected?!?

Ocramius commented 5 years ago

With a final class this is a real challenge as my DI can return a new instance each time or a shared instance, depending on how I configure it. Neither is workable.

Please depend on the MiddlewarePipeInterface:

https://github.com/zendframework/zend-stratigility/blob/9ea8435eac09be8ec2f6eafa72f5d41f11e2e823/src/MiddlewarePipeInterface.php#L15-L18

As for final, the complete and generic explanation about the adoption of more and more of the final keyword can be found at https://ocramius.github.io/blog/when-to-declare-classes-final/

The correct approach is to use a decorator that receives a MiddlewarePipeInterface as constructor argument (along with whatever you need), and implements MiddlewarePipeInterface itself, delegating execution when appropriate.

weierophinney commented 5 years ago

The decision was made because (a) the implementation is quite trivial, (b) we're providing MiddlewarePipeInterface now, which means (c) you can achieve things you'd normally do via extension using composition or by implementing the new interface.

I'm not sure what DI container you're using, exactly, so it's hard to provide examples. Perhaps you can give some more details? In zend-servicemanager, you could provide a factory that creates and returns your MiddlewarePipe instance, allowing you to map services to specific factories. Alternately, implement the interface, which allows you to have discrete classes.