Laravel

Collections

PHP autodoc-laravel tracks the item and key types of Laravel collections.

Collection analysis works the same whether the collection comes from a collect([...]) call or from an Eloquent query like Planet::all() or ->get().

Example

$planets = Planet::all();

return response()->json([
    'names' => $planets->pluck('name'),
    'total' => $planets->count(),
    'first' => $planets->first(),
]);

The documented response resolves each collection method against the model's column types:

{
    names: string[]
    total: number
    first: {
        id: number
        name: string
        // ... other Planet columns
    } | null
}

Supported methods

These Collection methods are currently recognized:

avg, average, contains, count, each, filter, first, flatten, get, groupBy, implode, isEmpty, isNotEmpty, keyBy, last, map, mapWithKeys, pluck, reject, reverse, skip, slice, sortBy, sortByDesc, sortDesc, sum, take, toArray, unique, values

How these methods affect types:

  • first, last and get return the collection item type. When you pass a default value, its type is included in the result; without one, null is.
  • pluck resolves the plucked property's type from the item shape, including keyed plucks like pluck('name', 'id').
  • Scalar methods have fixed return types matching Laravel's runtime behavior: sum is a number, count a non-negative integer, avg/average a number or null, isEmpty/isNotEmpty/contains a boolean, implode a string.
  • Methods like filter, sortBy, unique, reverse, take and skip pass the collection shape through unchanged. values drops the keys, toArray converts to a plain array.

Unrecognized methods fall back to regular code analysis, so custom collection classes and macros may still resolve through their own return types.

Analyzed callbacks

Callbacks passed to map, mapWithKeys and each are analyzed - both closures and arrow functions - so the resulting item shape comes from your actual callback code:

$planets = Planet::all();

return response()->json(
    $planets->map(fn ($planet) => [
        'id' => $planet->id,
        'label' => $planet->name,
    ])
);
{
    id: number
    label: string
}[]

Mutating models inside each()

each() returns the collection itself, but its callback is still analyzed. Attributes set on the callback parameter - for example with setAttribute - are merged into the collection's item type:

$planets = Planet::all();

$planets->each(function ($planet) {
    $planet->setAttribute('flag', true);
});

return $planets;

The documented response items contain all Planet columns plus flag: boolean. This works for a value-less $planets->each(...); statement as well, and attributes set conditionally inside the callback become optional fields.