In a recent podcast episode, I mentioned offhand how we don't like to add return types to our controller action methods. Today, I'll explain why that is.
First, it's important to note that we do like typing in general, including return types. Our default is to run PHPStan at level 5 or 6 in our applications. We've seen the benefits that static analysis can bring when refactoring and not accidentally introducing bugs.
If we like it so much, then why do we skip it for controller actions?
Consider how many different things you can return from a controller action? A view, a response, a JSON response, an array, a string, a redirect, and so on. This flexibility is great, but it means it can return lots of different types of data. We could represent all these possibilities with a huge union type, but it's pretty ugly.
Another option would be to specify the exact type each action returns. This cleans up that huge union type, but now it introduces brittleness. Let's say you initially return a view, but later refactor the action to return a redirect on one path, and the view on the other path. You'll now get a type error if you don't update your return type. But even worse, the error isn't actually an error. Laravel would have no trouble returning both types properly. This false positive is annoying!
The other factor in this decision is that the only thing calling our controller action is the framework itself. We're never going to call it ourselves and not handle the types properly. If Laravel is the only thing that calls it, and it's flexible enough to handle it, why add brittleness or false positive type errors? We aren't gaining any safety.
We use this same logic in other places too. For example the middleware
handle() method, or Livewire's
render() method. Basically anytime there's a method that supports lots of different return types and is only ever called by framework code.
Here to help,
P.S. Want help setting up PHPStan in your project? We've done it many times, and can get you set up quickly.