La clase Illuminate\Support\Collection es un envoltorio fluido para trabajar con arrays.
En lugar de invocar por separado las funciones nativas de arrays de PHP, permite transformar los datos de manera intuitiva encadenando métodos.
// Operación tradicional con arrays$names = array_filter( array_map(fn ($user) => $user['name'], $users), fn ($name) => $name !== null);// Con una colección$names = collect($users) ->pluck('name') ->filter() ->values();
Las colecciones son inmutables. Cada método devuelve una nueva instancia sin modificar la colección original, de modo que puedes operar con seguridad sin perder los datos de partida.
Se comporta como reduce, pero la callback no necesita devolver un valor. Es útil para modificar directamente un objeto existente.
class OrderStats{ public int $total = 0; public int $count = 0;}$orders = collect([ ['amount' => 100], ['amount' => 250], ['amount' => 50],]);$stats = $orders->reduceInto(new OrderStats, function (OrderStats $stats, array $order) { $stats->total += $order['amount']; $stats->count++;});$stats->total; // 400$stats->count; // 3
En reduce el retorno de la callback se convierte en el siguiente $carry, por lo que encaja bien con la agregación de valores primitivos. En reduceInto se muta directamente un objeto, dando lugar a un código más simple.
Para agregar sobre un escalar o un array, utiliza el paso por referencia (&) en la callback.
$collection = collect([1, 2, 3, 4, 5]);$even = $collection->reduceInto([], function (array &$result, int $value) { if ($value % 2 === 0) { $result[] = $value; }});// [2, 4]
Divide una colección grande en fragmentos del tamaño indicado. Es útil para procesamiento por lotes o para paginar en pantalla.
$users = collect(range(1, 100))->map(fn ($i) => ['id' => $i, 'name' => "Usuario {$i}"]);// Divide en trozos de 10$chunks = $users->chunk(10);// $chunks->count() === 10// Procesa cada lote$chunks->each(function (\Illuminate\Support\Collection $batch) { // Operaciones de BD, envío de correos, etc. por lote});
Los resultados de las consultas de Eloquent siempre son instancias de Illuminate\Database\Eloquent\Collection.
Esta clase extiende la Collection base, así que todos los métodos vistos están disponibles.
use App\Models\User;use App\Models\Order;// El resultado de get() es una colección$users = User::where('is_active', true)->get(); // Collection// Puedes usar directamente los métodos de colección$adminEmails = User::all() ->filter(fn ($user) => $user->role === 'admin') ->pluck('email');// También puedes manipular las relaciones ya cargadas$orders = Order::with('items')->where('status', 'completed')->get();$summary = $orders->map(fn ($order) => [ 'id' => $order->id, 'customer' => $order->user->name, 'item_count' => $order->items->count(), 'total' => $order->items->sum('price'),]);
El filtrado y la ordenación que pueda hacer la base de datos deben resolverse en el query builder (where, orderBy, etc.), no en la colección. Si filtras después de convertir a colección, cargarás en memoria todos los datos innecesarios.
Mientras que una colección normal carga en memoria todos los datos, LazyCollection aprovecha los generadores de PHP y procesa los elementos uno a uno.
Permite ahorrar memoria cuando trabajas con decenas de miles de registros.
use Illuminate\Support\LazyCollection;// Colección normal: carga todos los datos en memoria$users = User::all(); // Con 100 000 registros, todos están en memoria// LazyCollection: procesa uno a unoUser::cursor()->each(function (User $user) { // Procesa cada usuario individualmente // Solo un registro en memoria en cada instante});
use Illuminate\Support\LazyCollection;// A partir de una closure (generador)$lazy = LazyCollection::make(function () { $handle = fopen('large-file.csv', 'r'); while (($line = fgetcsv($handle)) !== false) { yield $line; } fclose($handle);});// El método cursor() de Eloquent devuelve una LazyCollection$lazy = User::where('is_active', true)->cursor();
use App\Models\Order;// Procesa todos los pedidos uno a uno (eficiente en memoria)Order::cursor() ->filter(fn ($order) => $order->amount > 100) ->each(fn ($order) => $order->sendConfirmationEmail());// Con cursor() se recuperan los pedidos uno a uno y filter/each los tratan en pipelineOrder::where('status', 'completed') ->cursor() ->filter(fn ($order) => $order->amount > 100) ->each(fn ($order) => $order->sendConfirmationEmail());
cursor() recupera los registros uno a uno de la base de datos, con lo que ahorra mucha memoria al procesar grandes cantidades. Ten en cuenta, sin embargo, que la conexión con la base de datos se mantiene activa hasta que finaliza el procesamiento.
$lazy = LazyCollection::make(function () { foreach (range(1, 1000000) as $i) { yield $i; }});// Salta los primeros 1000 y obtén los siguientes 100$page = $lazy->skip(1000)->take(100)->values();