Laravel: Understanding Collections’ Higher Order Messages
… and the beauty of them.
If may think that enough tinkering around Laravel’s Collections too much have made you some kind of Collection expert, but Higher Order Messages are one level above in understanding.
One thing I couldn’t grasp, and probably you either if you are reading this, is how they work and what problem they try to solve, but falter not, these are relatively easy to understand when you think about them as proxies to the real methods.
Get off my lawn, you dirty closure!
Higher Order Messages are basically properties that act like you were doing a very short closure. To better exemplify, let’s say we want to filter all users who are not admin.
$users = collect([
1 => [
'name' => 'John',
'age' => 31
'is_admin' => false,
],
2 => [
'name' => 'Mike',
'age' => 16
'is_admin' => true,
],
3 => [
'name' => 'Carmen',
'age' => 58
'is_admin' => false,
],
4 => [
'name' => 'Abby',
'age' => 24
'is_admin' => true,
],
]);
You can see that Mike and Abby are admins because the is_admin
is true
, so the first thing you could do to filter them should be to call the filter
method of the Collection to return those who are inside another Collection instance.
$admins = $users->filter(function (array $user) {
return $user['is_admin'];
});
While that line may work for some, we can make the filter a one line. The filter
method as a Higher Order Message by the same name. It will take the value we are using to “get” as the what the closure should return for each item in the collection, being a property or an array key.
$admins = $users->filter->is_admin;
And that’s it, it’s very simple.
What about sum, for example?
Some methods do not return collections, and that’s fine. For example, the sum
method returns the result of a sum on the value of each item.
In this case, we can sum the users who are admins:
$admins = $users->sum(function (array $user) {
return $user['is_admin'] ? 1 : 0;
});// 2
We can make that whole call into one line, since the sum
method actually does an additive operation in PHP which is compatible with booleans, where true
is 1
and false
is 0
. So, yes, we can sum booleans without any problem.
$admins = $users->sum->is_admin; // 2
Can you use methods? With arguments?
Higher Order Collection are also compatible with methods, including arguments to them. The method you pass will be used for each item, so let’s make an example.
This User
class has a convenient method that returns true
or false
if the age is above to what we’re asking.
class User extends Model
{
public function ageAbove(int $age)
{
return $this->age > $age;
}
}
Let’s assume we have a collection of these User
class instances. The old nasty way to filter them would be using a closure to execute on each of them.
$users = User::all();$adults = $users->filter(function (User $user) {
return $user->ageAbove(21);
});
And it gets more verbose when we have to include the age from a variable outside the closure.
$adults = $users->filter(function (User $user) use ($age) {
return $user->ageAbove($age);
});
But that can be, again, become a one line:
$adults = $users->filter->ageAbove(21);
And that’s all folks!