Higher order messages let you call collection methods using property-access syntax rather than writing a closure. You can retrieve a property or call a method on every element without any anonymous functions.
// Standard approach$names = $users->map(fn ($user) => $user->name);// Higher order message$names = $users->map->name;
$users->map->name means “map over each user and return its name property.”
When you access $collection->map as a property, the __get() method in the EnumeratesValues trait is called.
// src/Illuminate/Collections/Traits/EnumeratesValues.phppublic function __get($key){ if (! in_array($key, static::$proxies)) { throw new Exception("Property [{$key}] does not exist on this collection instance."); } return new HigherOrderCollectionProxy($this, $key);}
If the key is in the $proxies list, a HigherOrderCollectionProxy instance is returned. The proxy holds a reference to the collection and the method name.
Higher order messages are especially useful with Eloquent collections.
$users = User::with('posts')->get();// Call a method on each element$users->each->markAsVerified();// Retrieve a property from each element$names = $users->map->name;// Pass arguments to a method$users->each->sendPasswordReset('en');// Send a notification to each user$users->each->notify(new WelcomeNotification);
// Sum a property across all elements$totalPosts = $users->sum->post_count;// Maximum value of a property$highestScore = $users->max->score;// Average value of a property$averageAge = $users->avg->age;
// Group by a property$grouped = $users->groupBy->role;// Sort ascending by a property$sorted = $users->sortBy->name;// Sort descending by a property$sorted = $users->sortByDesc->created_at;
// Check whether every element satisfies a condition$allAdmins = $users->every->isAdmin();// Check whether at least one element satisfies a condition$hasActive = $users->contains->isActive();// Pass an argument to the method$allPro = $users->every->hasPlan('pro');
Higher order messages are concise, but they do not cover every scenario.
// Higher order messages: best for simple property access or method calls$emails = $users->map->email;$users->each->sendWelcomeMail();$admins = $users->filter->isAdmin();// Closures: use when logic is complex or arguments are dynamic$formatted = $users->map(function ($user) { return "{$user->name} <{$user->email}>";});$filtered = $users->filter(function ($user) use ($minAge, $role) { return $user->age >= $minAge && $user->role === $role;});
Use higher order messages when you are doing the same thing to every element — retrieving the same property or calling the same method. Switch to closures when the logic varies per element or depends on external variables.
Register the method as a macro first, then proxy it.
namespace App\Providers;use Illuminate\Support\Collection;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot(): void { Collection::macro('active', function () { return $this->filter(fn ($item) => $item->isActive()); }); Collection::proxy('active'); }}
// After registration, use it as a higher order message$activeUsers = $users->active;
For string collections, the proxy’s __call() attempts a static method call on the string. In practice, higher order messages work most naturally with Eloquent models or other objects.