Zum Hauptinhalt springen

Was sind Collections?

Die Klasse Illuminate\Support\Collection ist ein fluenter Wrapper für Array-Daten. Statt einzelne PHP-Standardfunktionen für Arrays aneinanderzureihen, können Sie Daten mit Methoden-Chaining intuitiv verarbeiten.
// Verarbeitung mit gewöhnlichen Array-Funktionen
$names = array_filter(
    array_map(fn ($user) => $user['name'], $users),
    fn ($name) => $name !== null
);

// Mit Collections
$names = collect($users)
    ->pluck('name')
    ->filter()
    ->values();
Collections sind immutable (unveränderlich). Jede Methode verändert die ursprüngliche Collection nicht, sondern liefert eine neue Instanz zurück. Sie können sicher arbeiten, ohne die Originaldaten zu verlieren.

Collections erzeugen

Helper collect()

Die gebräuchlichste Variante. Übergeben Sie ein Array, um eine Collection zu erzeugen.
use Illuminate\Support\Collection;

// Collection aus einem Array erzeugen
$users = collect([
    ['name' => 'Yamada Taro', 'age' => 28, 'role' => 'admin'],
    ['name' => 'Suzuki Hanako', 'age' => 34, 'role' => 'editor'],
    ['name' => 'Sato Jiro', 'age' => 22, 'role' => 'viewer'],
]);

// Auch verschachtelte Arrays sind möglich
$products = collect([
    ['name' => 'Notebook', 'price' => 120000, 'stock' => 5],
    ['name' => 'Maus', 'price' => 3500, 'stock' => 20],
    ['name' => 'Tastatur', 'price' => 8000, 'stock' => 12],
]);

Collection::make()

Entspricht collect(). Verwenden Sie diese Form, wenn Sie den Facade-Stil bevorzugen.
$collection = Collection::make([1, 2, 3]);

Collection::fromJson()

Erzeugt eine Collection aus einem JSON-String. Praktisch für die Verarbeitung externer API-Antworten.
$collection = Collection::fromJson('[{"name":"Yamada Taro"},{"name":"Suzuki Hanako"}]');

Häufig genutzte Methoden

map – jedes Element transformieren

Wendet eine Funktion auf jedes Element an und liefert eine neue Collection mit den transformierten Werten zurück.
$users = collect([
    ['name' => 'Yamada Taro', 'email' => '[email protected]'],
    ['name' => 'Suzuki Hanako', 'email' => '[email protected]'],
]);

// E-Mail-Adressen für die Anzeige maskieren
$masked = $users->map(function (array $user) {
    $parts = explode('@', $user['email']);
    return [
        'name' => $user['name'],
        'email' => substr($parts[0], 0, 2) . '***@' . $parts[1],
    ];
});

// [['name' => 'Yamada Taro', 'email' => 'ya***@example.com'], ...]

filter / reject – nach Bedingung filtern

filter() behält nur die Elemente, die der Bedingung entsprechen; reject() schließt diese aus.
$products = collect([
    ['name' => 'Notebook', 'price' => 120000, 'in_stock' => true],
    ['name' => 'Maus', 'price' => 3500, 'in_stock' => false],
    ['name' => 'Tastatur', 'price' => 8000, 'in_stock' => true],
]);

// Nur Produkte mit Lagerbestand
$inStock = $products->filter(fn ($product) => $product['in_stock']);

// Produkte ohne Lagerbestand ausschließen (reject ist die Umkehrung von filter)
$available = $products->reject(fn ($product) => ! $product['in_stock']);

// Ohne Argument entfernt filter() alle falsy-Werte
$names = collect(['Yamada', '', null, 'Suzuki', false])->filter()->values();
// ['Yamada', 'Suzuki']
Nach filter() können Indizes lückenhaft werden. Ein Aufruf von values() weist die Indizes ab 0 neu zu.

first / last – einzelnes Element ermitteln

Liefert das erste bzw. letzte Element, das die Bedingung erfüllt.
$orders = collect([
    ['id' => 1, 'status' => 'shipped', 'amount' => 5000],
    ['id' => 2, 'status' => 'pending', 'amount' => 12000],
    ['id' => 3, 'status' => 'pending', 'amount' => 3500],
]);

// Die nächste offene Bestellung ermitteln
$nextOrder = $orders->first(fn ($order) => $order['status'] === 'pending');
// ['id' => 2, 'status' => 'pending', 'amount' => 12000]

// Standardwert, falls keine Bedingung zutrifft
$order = $orders->first(fn ($order) => $order['status'] === 'cancelled', null);

// Letztes Element
$latest = $orders->last();

pluck – nur einen bestimmten Schlüssel extrahieren

Extrahiert aus verschachtelten Arrays oder Modellen ein bestimmtes Feld.
$users = collect([
    ['id' => 1, 'name' => 'Yamada Taro', 'department' => 'Entwicklung'],
    ['id' => 2, 'name' => 'Suzuki Hanako', 'department' => 'Vertrieb'],
    ['id' => 3, 'name' => 'Sato Jiro', 'department' => 'Entwicklung'],
]);

// Nur die Namen extrahieren
$names = $users->pluck('name');
// ['Yamada Taro', 'Suzuki Hanako', 'Sato Jiro']

// Mapping mit id als Schlüssel
$nameById = $users->pluck('name', 'id');
// [1 => 'Yamada Taro', 2 => 'Suzuki Hanako', 3 => 'Sato Jiro']

groupBy – nach einem Schlüssel gruppieren

$users = collect([
    ['name' => 'Yamada Taro', 'department' => 'Entwicklung'],
    ['name' => 'Suzuki Hanako', 'department' => 'Vertrieb'],
    ['name' => 'Sato Jiro', 'department' => 'Entwicklung'],
    ['name' => 'Tanaka Misaki', 'department' => 'Vertrieb'],
]);

$byDepartment = $users->groupBy('department');
// [
//   'Entwicklung' => [['name' => 'Yamada Taro', ...], ['name' => 'Sato Jiro', ...]],
//   'Vertrieb'    => [['name' => 'Suzuki Hanako', ...], ['name' => 'Tanaka Misaki', ...]],
// ]

// Gruppenschlüssel dynamisch per Closure bestimmen
$byFirstChar = $users->groupBy(fn ($user) => mb_substr($user['name'], 0, 1));

sortBy / sortByDesc – sortieren

$products = collect([
    ['name' => 'Notebook', 'price' => 120000],
    ['name' => 'Maus', 'price' => 3500],
    ['name' => 'Tastatur', 'price' => 8000],
]);

// Preis aufsteigend
$cheapFirst = $products->sortBy('price');

// Preis absteigend
$expensiveFirst = $products->sortByDesc('price');

// Nach mehreren Schlüsseln sortieren
$sorted = $products->sortBy([
    ['price', 'asc'],
    ['name', 'asc'],
]);

each – Verarbeitung pro Element ausführen

Für Vorgänge mit Seiteneffekten (Log-Ausgabe, E-Mail-Versand usw.). Die Collection selbst wird nicht verändert.
$orders = collect([
    ['id' => 1, 'user_id' => 10, 'amount' => 5000],
    ['id' => 2, 'user_id' => 11, 'amount' => 12000],
]);

$orders->each(function (array $order) {
    \Log::info("Verarbeite Bestellung #{$order['id']}", ['amount' => $order['amount']]);
    // Benachrichtigung senden, Job dispatchen usw.
});

// Rückgabe von false bricht die Schleife ab
$orders->each(function (array $order) {
    if ($order['amount'] > 10000) {
        return false; // Schleife verlassen
    }
    // ...
});

flatMap – mappen und eine Ebene flatten

Wandelt jedes Element in ein Array um und flacht das Ergebnis um eine Ebene ab.
$users = collect([
    ['name' => 'Yamada Taro', 'tags' => ['php', 'laravel']],
    ['name' => 'Suzuki Hanako', 'tags' => ['javascript', 'vue']],
]);

// Alle Tags aller Nutzer als flache Liste
$allTags = $users->flatMap(fn ($user) => $user['tags']);
// ['php', 'laravel', 'javascript', 'vue']

reduce – aggregieren

Reduziert die gesamte Collection auf einen einzelnen Wert.
$orders = collect([
    ['product' => 'Notebook', 'quantity' => 1, 'price' => 120000],
    ['product' => 'Maus', 'quantity' => 2, 'price' => 3500],
    ['product' => 'Tastatur', 'quantity' => 1, 'price' => 8000],
]);

// Gesamtsumme berechnen
$total = $orders->reduce(
    fn ($carry, $order) => $carry + ($order['price'] * $order['quantity']),
    0
);
// 135000
Für einfache Summen können Sie sum() verwenden: $orders->sum(fn ($o) => $o['price'] * $o['quantity'])

reduceInto – in ein Objekt aggregieren

Reduziert ähnlich wie reduce, die Callback-Funktion muss aber keinen Rückgabewert liefern. Praktisch, wenn Sie ein bestehendes Objekt direkt mutieren möchten.
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
Bei reduce wird der Rückgabewert der Callback zum nächsten $carry, was sich gut für primitive Werte eignet. reduceInto mutiert dagegen kontinuierlich ein Objekt und führt so zu übersichtlicherem Code.
Möchten Sie in einen Skalar oder ein Array aggregieren, verwenden Sie in der Callback eine Referenz (&).
$collection = collect([1, 2, 3, 4, 5]);

$even = $collection->reduceInto([], function (array &$result, int $value) {
    if ($value % 2 === 0) {
        $result[] = $value;
    }
});

// [2, 4]

chunk – aufteilen

Zerlegt eine große Collection in Blöcke einer angegebenen Größe. Praktisch für Batch-Verarbeitung oder Anzeige.
$users = collect(range(1, 100))->map(fn ($i) => ['id' => $i, 'name' => "Nutzer{$i}"]);

// In Blöcke à 10 Einträgen teilen
$chunks = $users->chunk(10);
// $chunks->count() === 10

// Pro Batch verarbeiten
$chunks->each(function (\Illuminate\Support\Collection $batch) {
    // DB-Operationen oder E-Mail-Versand pro Batch
});

Methoden-Chaining

Die eigentliche Stärke von Collections liegt im Methoden-Chaining. Mehrere Operationen lassen sich verketten, sodass komplexe Datentransformationen in einem einzigen Ausdruck möglich werden.
$orders = collect([
    ['customer' => 'Yamada Taro', 'status' => 'completed', 'amount' => 5000, 'category' => 'Elektronik'],
    ['customer' => 'Suzuki Hanako', 'status' => 'pending',   'amount' => 12000, 'category' => 'Elektronik'],
    ['customer' => 'Sato Jiro', 'status' => 'completed', 'amount' => 3500, 'category' => 'Schreibwaren'],
    ['customer' => 'Tanaka Misaki', 'status' => 'completed', 'amount' => 8000, 'category' => 'Elektronik'],
    ['customer' => 'Ito Kenichi', 'status' => 'cancelled', 'amount' => 2000, 'category' => 'Schreibwaren'],
]);

// Abgeschlossene Elektronik-Bestellungen nach Betrag absteigend sortieren und Name und Betrag extrahieren
$result = $orders
    ->filter(fn ($order) => $order['status'] === 'completed')
    ->filter(fn ($order) => $order['category'] === 'Elektronik')
    ->sortByDesc('amount')
    ->map(fn ($order) => [
        'customer' => $order['customer'],
        'amount'   => number_format($order['amount']) . ' Yen',
    ])
    ->values();

// [
//   ['customer' => 'Tanaka Misaki', 'amount' => '8,000 Yen'],
//   ['customer' => 'Yamada Taro', 'amount' => '5,000 Yen'],
// ]

Zusammenspiel mit Eloquent

Ergebnisse von Eloquent-Abfragen werden stets als Instanzen von Illuminate\Database\Eloquent\Collection zurückgegeben. Diese erbt von der Basis-Collection, sodass alle oben gezeigten Methoden zur Verfügung stehen.
use App\Models\User;
use App\Models\Order;

// Ergebnis von get() ist eine Collection
$users = User::where('is_active', true)->get(); // Collection

// Collection-Methoden direkt verwendbar
$adminEmails = User::all()
    ->filter(fn ($user) => $user->role === 'admin')
    ->pluck('email');

// Auch bereits geladene Relationen sind Collections
$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'),
]);
Filterung und Sortierung, die die Datenbank effizient erledigen kann, sollten Sie über den Query Builder (where, orderBy usw.) durchführen und nicht erst auf der Collection anwenden. Andernfalls laden Sie unnötige Daten in den Speicher.

Eloquent-spezifische Collection-Methoden

Eloquent\Collection verfügt zusätzlich über einige eigene Methoden.
$users = User::all();

// Model per ID finden
$user = $users->find(1);

// Collection der Primärschlüssel
$ids = $users->modelKeys(); // [1, 2, 3, ...]

// Relationen gebündelt nachladen
$users->load('orders', 'profile');

// Differenz- und Schnittmenge
$diff = $users->diff($otherUsers);
$intersect = $users->intersect($otherUsers);

Lazy Collections

Während gewöhnliche Collections die gesamten Daten in den Arbeitsspeicher laden, nutzt eine LazyCollection PHP-Generatoren und verarbeitet die Daten Element für Element. Bei mehreren Zehntausend Datensätzen oder mehr sparen Sie damit deutlich Arbeitsspeicher.
use Illuminate\Support\LazyCollection;

// Normale Collection: lädt alle Daten in den Speicher
$users = User::all(); // 100.000 Einträge landen komplett im Speicher

// LazyCollection: Element für Element
User::cursor()->each(function (User $user) {
    // Nutzer einzeln verarbeiten
    // Immer nur ein Element wird im Speicher gehalten
});

LazyCollections erzeugen

use Illuminate\Support\LazyCollection;

// Aus einer Closure (Generator) erzeugen
$lazy = LazyCollection::make(function () {
    $handle = fopen('large-file.csv', 'r');

    while (($line = fgetcsv($handle)) !== false) {
        yield $line;
    }

    fclose($handle);
});

// Die Methode cursor() von Eloquent liefert eine LazyCollection
$lazy = User::where('is_active', true)->cursor();

Batch-Verarbeitung großer Datenmengen

use App\Models\Order;

// Alle Bestellungen einzeln verarbeiten (speicheroptimal)
Order::cursor()
    ->filter(fn ($order) => $order->amount > 10000)
    ->each(fn ($order) => $order->sendConfirmationEmail());

// Mit cursor() Datensatzweise abrufen und mit filter/each in einer Pipeline verarbeiten
Order::where('status', 'completed')
    ->cursor()
    ->filter(fn ($order) => $order->amount > 10000)
    ->each(fn ($order) => $order->sendConfirmationEmail());
cursor() holt Datensätze einzeln aus der Datenbank und spart bei großen Ergebnismengen erheblich Speicher. Beachten Sie jedoch, dass die Datenbankverbindung bis zum Ende der Verarbeitung offen bleibt.

Paginierung mit take und skip

$lazy = LazyCollection::make(function () {
    foreach (range(1, 1000000) as $i) {
        yield $i;
    }
});

// Die ersten 1000 überspringen, die nächsten 100 nehmen
$page = $lazy->skip(1000)->take(100)->values();

Zusammenfassung

MethodeBeschreibung
collect($array)Collection erzeugen
map($callback)Jedes Element transformieren
filter($callback)Nach Bedingung filtern
reject($callback)Elemente ausschließen, die auf die Bedingung passen
first($callback)Erstes Element ermitteln, das die Bedingung erfüllt
pluck($key)Werte eines bestimmten Schlüssels extrahieren
groupBy($key)Nach einem Schlüssel gruppieren
sortBy($key)Aufsteigend sortieren
sortByDesc($key)Absteigend sortieren
each($callback)Verarbeitung pro Element (Seiteneffekte)
flatMap($callback)Mappen und eine Ebene flatten
reduce($callback, $initial)Aggregation zu einem Einzelwert
chunk($size)In Blöcke einer festgelegten Größe teilen
values()Indizes neu zuweisen
sum($key)Summe berechnen
count()Anzahl der Elemente
Collections lesen sich deutlich klarer als geschachtelte Array-Funktionen.
// Mit Array-Funktionen
$result = array_values(array_filter(
    array_map(fn ($u) => $u['name'], $users),
    fn ($name) => strlen($name) > 2
));

// Mit einer Collection
$result = collect($users)
    ->pluck('name')
    ->filter(fn ($name) => strlen($name) > 2)
    ->values()
    ->all();
  • Normale Collection: einige Hundert bis wenige Tausend Datensätze. Einfach und intuitiv.
  • LazyCollection: mehrere Zehntausend Datensätze oder mehr, wenn Sie Speicher sparen möchten. In Kombination mit cursor() besonders wirkungsvoll.
  • get() liefert bei Eloquent eine normale Collection, cursor() eine LazyCollection.
Zuletzt geändert am 13. Juli 2026