I recently witten a post about currying and during my research one of the examples that AI gave me was this.
function taxedAmount(int|float $rate)
{
return fn(int|float $amount) => $amount * (1 + $rate / 100);
}
$twentyProcent = taxedAmount(20);
$priceWithTax = $twentyProcent(100);
And to me that looked a lot like an invokable class.
class TaxedAmount
{
public function __construct(private int|float $rate)
{}
public function __invoke(int|float $amount)
{
return $amount * (1 + $this->rate / 100)
}
}
$instance = new TaxedAmount(20);
$priceWithTax = $instance(100);
In the PHP frameworks there are several places that execute invokable classes. The first things that come to mind are controllers and events.
I'm wondering what the experience is to use a wrapped closure instead of an invokable class?
Testing a Laravel controller
Setup
In composer.json I added
"autoload": {
"files": [ "app/functions.php" ]
}
The functions.php contains
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/Functions'));
foreach ($iterator as $item) {
if ($item->isFile() && $item->getExtension() === 'php') {
include $item->getPathname();
}
}
Creating the route
In the app/Functions/Controllers directory I added closureController.php.
namespace App\Http\Controllers; // fake it till you make it
use Illuminate\Http\Request;
function closure() {
return fn(Request $request) => $request->uri()->path();
}
In routes/web.php I added, Route::get('closure', \App\Http\Controllers\closure());
. And I got closure as response in the browser
Why did it work?
I discovered that the Laravel router checks if the action is a closure or not. And if it is the closure will get executed.
Other places in Laravel where you could use a wrapped closure
Any place where the framework accepts anonymus functions. I'm looking at the ServiceProvider
child classes where anonymus functions are used frequently.
Conclusion
Because I used arrow functions in my wrapped closure functions it seems like they require less typing. But if you use regular functions the typing will be almost the same.
The wrapped closure function won't allow you to autowire dependencies. The only time I go for constructor dependencies using an invokalbe class is when they are for a private method.
The only benefit of wrapped functions is that they can be placed in a single purpose file, and this makes them testable.
But you need the extra setup for the functions to be discoverable.
While it was a fun idea to entertain, I don't think I'm going to use wrapped closures a lot.
Top comments (0)