Los mensajes de orden superior (Higher-order Messages) son una sintaxis para invocar métodos de una colección accediendo a ellos como si fueran propiedades. Sin escribir una callback, puedes llamar a un método o acceder a una propiedad de cada elemento.
// Forma habitual$names = $users->map(fn ($user) => $user->name);// Forma con mensajes de orden superior$names = $users->map->name;
$users->map->name significa «extrae la propiedad name de cada usuario y aplica map».
Cuando accedes a algo como $collection->map como si fuera una propiedad, se invoca __get() del trait EnumeratesValues.
// 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);}
Si el nombre está en $proxies, se devuelve una instancia de HigherOrderCollectionProxy. Este proxy conserva la colección y el nombre del método.
Los mensajes de orden superior son especialmente útiles con colecciones de Eloquent.
$users = User::with('posts')->get();// Llamada a método: actualiza el estado de cada usuario$users->each->markAsVerified();// Acceso a propiedad: obtén solo los nombres$names = $users->map->name;// Con argumentos$users->each->sendPasswordReset('es');// Envío de notificación$users->each->notify(new WelcomeNotification);
$activeUsers = $users->filter->isActive();// Deja solo los usuarios para los que isActive() devuelve true// Equivale a $users->filter(fn ($user) => $user->isActive())$inactiveUsers = $users->reject->isActive();
// Suma la propiedad post_count de cada usuario$totalPosts = $users->sum->post_count;// Máximo de la propiedad score$highestScore = $users->max->score;// Media de la propiedad age$averageAge = $users->avg->age;
// Agrupar por la propiedad role$grouped = $users->groupBy->role;// Ordenar ascendentemente por la propiedad name$sorted = $users->sortBy->name;// Ordenar descendentemente por created_at$sorted = $users->sortByDesc->created_at;
// Comprueba si todos son administradores$allAdmins = $users->every->isAdmin();// Comprueba si al menos uno está activo$hasActive = $users->contains->isActive();// Comprueba si todos tienen un plan concreto$allPro = $users->every->hasPlan('pro');
También se pueden usar en colecciones de cadenas. El __call() del proxy trata las cadenas como si fueran una llamada estática.
$names = collect(['alice', 'bob', 'charlie']);// Para colecciones de cadenas suele ser más claro usar una closure$upper = $names->map(fn ($name) => strtoupper($name));// ['ALICE', 'BOB', 'CHARLIE']
Para usar mensajes de orden superior con una colección de cadenas, el método debe existir estáticamente en el tipo string. Normalmente, encajan mejor con colecciones de modelos Eloquent o clases propias.
Los mensajes de orden superior son concisos, pero no encajan en todos los casos.
// Mensaje de orden superior: adecuado para obtener propiedades o llamar a métodos simples$emails = $users->map->email;$users->each->sendWelcomeMail();$admins = $users->filter->isAdmin();// Closure: adecuada para lógica compleja o cuando se necesitan argumentos$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;});
Cuando quieres «obtener la misma propiedad de cada elemento» o «llamar al mismo método en cada elemento», los mensajes de orden superior son más legibles. Si la condición es compleja o los argumentos son dinámicos, usa una closure.
Para aprovechar el mecanismo de HigherOrderCollectionProxy a través del trait EnumeratesValues, llama a Collection::proxy() para añadir el método al conjunto de proxies.
namespace App\Providers;use Illuminate\Support\Collection;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot(): void { // Añade una macro personalizada al conjunto de proxies Collection::macro('active', function () { return $this->filter(fn ($item) => $item->isActive()); }); Collection::proxy('active'); }}
// Tras el registro, ya se puede usar como mensaje de orden superior$activeUsers = $users->active;