Zum Hauptinhalt springen

Was sind Higher-Order Messages?

Higher-Order Messages sind eine Syntax, mit der Sie Collection-Methoden wie einen Property-Zugriff aufrufen. Ohne einen Callback zu schreiben, können Sie für jedes Element eine Methode aufrufen oder eine Property abfragen.
// Klassische Schreibweise
$names = $users->map(fn ($user) => $user->name);

// Schreibweise mit Higher-Order Message
$names = $users->map->name;
$users->map->name bedeutet „aus jedem Nutzer die Property name entnehmen und mit map verarbeiten”.

Funktionsweise — HigherOrderCollectionProxy

Wenn Sie wie in $collection->map als Property zugreifen, wird __get() des Traits EnumeratesValues aufgerufen.
// src/Illuminate/Collections/Traits/EnumeratesValues.php
public 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);
}
Ist der Methodenname in $proxies enthalten, wird eine Instanz von HigherOrderCollectionProxy zurückgegeben. Dieser Proxy hält die Collection und den Methodennamen fest.

Property-Zugriff über __get proxieren

Greifen Sie danach auf eine Property zu (->name), wird __get() des Proxys aufgerufen.
// src/Illuminate/Collections/HigherOrderCollectionProxy.php
public function __get($key)
{
    return $this->collection->{$this->method}(function ($value) use ($key) {
        return is_array($value) ? $value[$key] : $value->{$key};
    });
}
Damit ist $users->map->name äquivalent zu:
$users->map(fn ($user) => $user->name);

Methodenaufruf über __call proxieren

Rufen Sie im Anschluss eine Methode auf (->activate()), wird __call() des Proxys ausgeführt.
public function __call($method, $parameters)
{
    return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {
        return is_string($value)
            ? $value::{$method}(...$parameters)
            : $value->{$method}(...$parameters);
    });
}
$users->each->activate() entspricht:
$users->each(fn ($user) => $user->activate());

Liste unterstützter Methoden

Welche Methoden als Higher-Order Message verwendbar sind, definiert das Array $proxies.
protected static $proxies = [
    'average', 'avg',
    'contains', 'doesntContain', 'some',
    'each', 'every',
    'filter', 'reject',
    'first', 'last',
    'flatMap', 'map',
    'groupBy', 'keyBy',
    'hasMany', 'hasSole',
    'max', 'min', 'sum', 'percentage',
    'partition',
    'skipUntil', 'skipWhile',
    'sortBy', 'sortByDesc',
    'takeUntil', 'takeWhile',
    'unique',
    'unless', 'until', 'when',
];
Eigene Methoden fügen Sie über Collection::proxy() hinzu.
Collection::proxy('myCustomMethod');

Praktische Anwendungsfälle

Collections von Eloquent-Modellen

Higher-Order Messages sind bei Eloquent-Collections besonders praktisch.
$users = User::with('posts')->get();

// Methodenaufruf: Status jedes Nutzers aktualisieren
$users->each->markAsVerified();

// Property-Zugriff: nur Namen entnehmen
$names = $users->map->name;

// Argument an die Methode übergeben
$users->each->sendPasswordReset('ja');

// E-Mails versenden
$users->each->notify(new WelcomeNotification);

Filtern

$activeUsers = $users->filter->isActive();

// behält nur Nutzer, deren isActive() true liefert
// äquivalent zu $users->filter(fn ($user) => $user->isActive())

$inactiveUsers = $users->reject->isActive();

Aggregation

// Summe über die Property post_count jedes Nutzers
$totalPosts = $users->sum->post_count;

// Maximum der Property score jedes Nutzers
$highestScore = $users->max->score;

// Durchschnitt der Property age jedes Nutzers
$averageAge = $users->avg->age;

Gruppieren und sortieren

// Nach der Property role gruppieren
$grouped = $users->groupBy->role;

// Aufsteigend nach der Property name sortieren
$sorted = $users->sortBy->name;

// Absteigend nach der Property created_at sortieren
$sorted = $users->sortByDesc->created_at;

Mit flatMap verschachtelte Strukturen entpacken

// Die posts-Beziehung jedes Nutzers zu einer einzigen Collection zusammenführen
$posts = $users->flatMap->posts;

Bedingungen prüfen

// Sind alle Administratoren?
$allAdmins = $users->every->isAdmin();

// Gibt es mindestens einen aktiven Nutzer?
$hasActive = $users->contains->isActive();

// Haben alle einen bestimmten Plan?
$allPro = $users->every->hasPlan('pro');

Collections aus Strings

Auch bei Collections aus Strings können Sie sie nutzen. Der __call()-Proxy ruft die Methode bei Strings als statische Methode auf.
$names = collect(['alice', 'bob', 'charlie']);

// Bei String-Collections ist eine Closure explizit
$upper = $names->map(fn ($name) => strtoupper($name));
// ['ALICE', 'BOB', 'CHARLIE']
Für Higher-Order Messages auf String-Collections muss die Methode statisch für den String-Typ definiert sein. Natürlicher ist der Einsatz bei Collections von Eloquent-Modellen oder eigenen Klassen.

Vergleich mit klassischen Closures

Higher-Order Messages sind kompakt, decken aber nicht jede Situation ab.
// Higher-Order Message: gut für schlichte Property-Abfragen oder Methodenaufrufe
$emails = $users->map->email;
$users->each->sendWelcomeMail();
$admins = $users->filter->isAdmin();

// Closure: passend bei komplexer Logik oder Argumenten
$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;
});
Wenn Sie „die gleiche Property aus jedem Element ziehen” oder „die gleiche Methode auf jedem Element aufrufen”, ist eine Higher-Order Message besser lesbar. Bei komplexen Bedingungen oder dynamischen Argumenten greifen Sie zur Closure.

Higher-Order Messages in eigenen Klassen einsetzen

Um den Mechanismus von HigherOrderCollectionProxy über den Trait EnumeratesValues zu nutzen, registrieren Sie Methoden per Collection::proxy() als Proxy-Ziele.
namespace App\Providers;

use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // Eigenes Macro als Proxy-Ziel registrieren
        Collection::macro('active', function () {
            return $this->filter(fn ($item) => $item->isActive());
        });

        Collection::proxy('active');
    }
}
// Nach der Registrierung als Higher-Order Message verwendbar
$activeUsers = $users->active;

Nächste Schritte

Conditionable-Trait

Lernen Sie die interne Implementierung von when() / unless() und deren Einsatz im QueryBuilder oder in eigenen Klassen.
Zuletzt geändert am 13. Juli 2026