Jens Segers on Sep 22 2017

Goodbye controllers, hello request handlers

A lot has changed in the PHP landscape over the past years. We started using more design patterns and things like the DRY and SOLID principles. But not a lot has changed for Controllers right?

If you have worked on large applications before, you might have noticed that you end up with bloated controllers sooner or later. Even if you use repositories or service classes to extract logic from the controller, the amount of dependencies, methods and lines of code will grow over time.

Let me introduce you to request handlers. The concept is very simple, yet very unknown to a lot of PHP developers. A request handler is basically a single action controller, which results in a more clear request to response flow. This concept has similarities with the Action-Domain-Responder pattern which was proposed by Paul M. Jones, an alternative for the MVC pattern.

A great way to build request handlers is using invokable classes. Invokable classes are classes that use PHP's magic __invoke method, turning them into a Callable, which allows them to be called as a function. Here is a simple example of an invokable class:

class Greeting
    public function __invoke($name)
        echo 'Hello ' . $name;

$welcome = new Greeting();
$welcome('John Doe'); // Hello John Doe

At this point you are probably thinking; "Why would I do that?". I know, this is a bit of an absurd example. But it makes a lot of sense when used in combination with code that expects callables and dependency injection. A great use case is request handling with routes in Laravel or Slim:

Route::get('/{name}', Greeting::class);

Did that just blow your mind? No? Let's compare that to what you would have normally written:

Route::get('/{name}', '[email protected]');

Still not? Other than nicer looking code, there are more benefits. Let me go ahead and compare some advantages of using request handlers vs. controllers.

Single responsibility

The very first principle of SOLID is the 'Single responsibility'. In my opinion, controllers with many actions kind of break this principle. Request handlers provide a nice solution to separate these actions into their own classes, making them easier to maintain, refactor and test.

Here's an example of 2 request handlers extracted from a UsersController, which handled both editing and saving of a user's profile:

class EditUserHandler
    public function __construct(
        UserRepository $repository,
        Twig $twig
    ) {

    public function __invoke(Request $request, Response $response)

class UpdateUserHandler
    public function __construct(
        UserRepository $repository,
        UpdateUserValidator $validator,
        ImageManager $resizer,
        Filesystem $storage
    ) {

    public function __invoke(Request $request, Response $response)

Which brings us to the next advantage;


Have you written unit tests for your controllers recently? You probably ended up creating mocked dependencies that were not even related to your test. Because request handlers split up the different controller actions into separate classes, you only have to inject or bind mocks for that specific action.

Recently Jeffrey Way suggested this on Twitter;

Testing Tip: Make your feature test classes as specific as possible, and then use each test to describe an important rule/ability.

This is basically what will happen naturally if you have a test file for each request handler. This is such a great improvement over those huge controller test files.


PhpStorm and other editors have powerful refactoring options. But if you use the default Laravel or Slim way of binding controller methods to routes, you probably ran into issues before. Renaming this:

Route::get('/{name}', Greeting::class);

Is just so much easier than this:

Route::get('/{name}', '[email protected]');


Request handlers offer a great alternative for controllers. Controller actions are split into individual request handler classes, responsible for a single action. This results in code that is easier to maintain, refactor and test.

Should you go ahead and replace all your controllers with request handlers? Probably not. For small applications it might make sense to group actions together just for simplicity. I only discovered request handlers when I started working at Teamleader, and I don't feel the need to go back to controllers anytime soon.

If something is unclear or you have questions, let me know by leaving a comment below and I will update this article.


bdrasht 1 year ago

Thanks, would have been a nice talk on the last PHP meetup at Teamleader.

te7ahoudini 1 year ago

great article i really liked the idea

davedriesmans 1 year ago

What articles/books/videos would you suggest if you want to dig a bit deeper into it?

Mononeon 1 year ago

$welcome = function () { echo 'Hello ' . $name; } $welcome('John Doe'); // Hello John Doe

wow Goodbye classes, hello functions

Jens Segers 1 year ago

@Mononeon that is indeed the simplified version. But anonymous functions don't have any of the advantages I described in the article.

Gunnlög 1 year ago

What is the difference to ADR? To me it looks like it is the same.

Jens Segers 1 year ago

@Gunnlög ADR is the concept, request handlers are an implementation of the action.

Steve 1 year ago

I've been using this a lot quite recently, and I've found it refreshing. Yes, you end up with more classes, but each Action (Request Handler) is so descriptive and specific that it's easier to reason about.

@davedriesmans See pmjones/adr and Martin Bean's blog post

I've found that extending Laravel's default App\Http\Controllers\Controller worked pretty well, letting me hook up middleware, use one-off validation, etc. all those little controller conveniences.

If you start to feel like you're repeating yourself across a group of related Actions, just make a parent class or extract commonality to some traits.

ericlagarda 1 year ago

How can I inject a ModelRepository into a Handler? No way to do it. Thanks

Jens Segers 1 year ago

@ericlagarda Depends on your framework/container. Laravel for example will auto wire dependencies on your constructor via reflection

Cherif 1 year ago

I dont think this is a good implementation of ADR, it dosent remove the Controller/Action from the UI layer yes UI layer the Controller/Action and the view are the components of the UI. The handlers are Application Services simply so they accepts commands (your request) and the commands should be validated. What you did is a tight coupling between the UI and the Application layer (handlers) the UI is a client to the Application services and the application services should be clients to the domain and the handlers shouldn't depend on the templating system or any response you can use specialized infrastructure services for this like transformers

olvlvl 1 year ago

Great article, but I'd rather leave HTTP business to controllers and use a command dispatcher and command handlers, so I can use the same commands from CLI, messaging, or whatever… Nowadays, controllers are one in many input sources. You shouldn't have your business logic in there.

Mahmoud Zalt 1 year ago

Great article, you may need to check the Porto Architecture

nonya123 1 year ago

a mostly good article, the negative part being the laravel typical reliance on static functions, rather than using a router service.. but nobody is perfect, I guess.

Jens Segers 1 year ago

@nonya123 the Laravel code is just an example. It applies to any framework or router you use.

Max Gaurav 1 year ago

The article kind of describes the PORTO pattern over the standard MVC pattern.

shadowhand 1 year ago

The only problem with this is that the handler should be returning a response, not receiving it as a parameter. In pseudo-code: fn(request): response is the ideal signature. If you are using PSR-7 then you probably want http-interop/http-factory to create those responses.

@Cherif using this pattern doesn't exclude the use of CQRS or CommandBus. The handler only deals with HTTP concerns and calls domain functions to produce the data needed for the response.

Jens Segers 1 year ago

@shadowhand The request being passed as a parameter is something typical in Laravel, but not related to the request handler concept. Implementing this in PSR 15 framework would return a response like you described.

Piero Recchia 1 year ago

Great article, this approach is used in Zend Expressive, i used without know it name

Eduardo Aranda 1 year ago

Would it be the same as using single action controllers ?

Tomas Votruba 1 year ago

I really like this approach moving from strings to

I've added similar support to Nette:

Alex Miles 1 year ago

Eduardo: Yes, although in Jens' example he uses class name resolution (Greeting::class), which makes it easier for the IDE to perform refactoring and code-completion out-of-the-box than if the class name was passed as a plain old string, as in the Laravel docs.

Junior Grossi 1 year ago

Hey, first thanks for the post. It's very, very interesting, really. Once you're using Laravel too I'd like to ask how you're structuring your folders. Do you save it in the same Controllers folder, like App\Http\Controllers\GreetingsHandler.php or do you have a custom App\Http\Handlers\Greetings.phpfor example? Thanks and congrats!

zvek3te 1 year ago

Cool, here is one framework I'm working on since June, it follows same thing you wrote here

SamAsEnd 1 year ago


Iman Ghafoori 1 year ago

An other way of reaching single responsibility in your controllers is described here :

Steven 1 year ago

find here Thanks , I have just been searching for info about this subject for ages and yours is the best I've came upon so far. But, what concerning the bottom line? Are you certain in regards to the supply?

Mico Barac 1 year ago

This looks cool, with a single function. What about a more complex controller that contains multiple actions? How do you convert it to handler using this approach?

Maximo 11 months ago

It should therefore be not surprising that, to experience total health and fitness, we need to manage the 3 (3) elements of ourselves - mind, body and spirit. It is significant that you just oversee the youngsters when they're brushing their teeth. When we travel as a family we always have a kitchenette inside the college accommodation so that we can easily result in the majority of our meals with food we know and after that have one meal out a day. mount kailash mystery -

Bour 10 months ago

Thank you very much for this explanation , I've only one question if you don't mind ? How you can structure your folder and please could you answer the question of @Mico Barac . Thanks

thearyanahmed 8 months ago

Does invokeable controller allows route model binding?I'm having some trouble with this.

MauseDap 1 month ago

Хотел спросить про программу,нужен хороший софт для добавления друзей в ВК

asdasd 1 month ago


Binaya Adhikari 4 weeks ago

lazywe 5 days ago

good job

EllMitnex 22 hours ago

Stilnox Buy Synthroid Online No Rx viagra Levitra Wirkungszeit Hplc Methods For Amoxicillin Clavulanic Acid Viagra Bestellen Apotheke