Laravel Collection Macros, Mixins &amp; Proxies | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com) [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles  ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

  [ home ](https://www.msaied.com)    [ articles ](https://www.msaied.com/articles)    Extending Laravel Collections: Macros, Mixins, and Higher-Order Proxies        On this page       1. [  Why Extend Collections at All? ](#why-extend-collections-at-all)
2. [  Macros: One-Off Domain Methods ](#macros-one-off-domain-methods)
3. [  Mixins: Grouping Related Macros ](#mixins-grouping-related-macros)
4. [  Higher-Order Proxies: Chainable Magic ](#higher-order-proxies-chainable-magic)
5. [  Lazy Collections and Macros ](#lazy-collections-and-macros)
6. [  Testing Your Macros ](#testing-your-macros)
7. [  Key Takeaways ](#key-takeaways)

  ![Extending Laravel Collections: Macros, Mixins, and Higher-Order Proxies](https://cdn.msaied.com/312/7bf5ac9ba3c8384848342d23b87fef21.png)

  #laravel   #collections   #macros   #php  

 Extending Laravel Collections: Macros, Mixins, and Higher-Order Proxies 
=========================================================================

     28 Jun 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Why Extend Collections at All?  ](#why-extend-collections-at-all)
2. [  02   Macros: One-Off Domain Methods  ](#macros-one-off-domain-methods)
3. [  03   Mixins: Grouping Related Macros  ](#mixins-grouping-related-macros)
4. [  04   Higher-Order Proxies: Chainable Magic  ](#higher-order-proxies-chainable-magic)
5. [  05   Lazy Collections and Macros  ](#lazy-collections-and-macros)
6. [  06   Testing Your Macros  ](#testing-your-macros)
7. [  07   Key Takeaways  ](#key-takeaways)

 Why Extend Collections at All?
------------------------------

Laravel's `Collection` class covers the common 80%, but real domain code always needs more. You could reach for a static helper, a standalone function, or a one-off `map()` chain — but each of those scatters intent across the codebase. Macros and mixins let you encode domain vocabulary directly on the collection, so call sites read like prose.

---

Macros: One-Off Domain Methods
------------------------------

A macro is the simplest extension point. Register it in a service provider and it becomes available on every `Collection` instance.

```php
// app/Providers/CollectionServiceProvider.php
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;

class CollectionServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Collection::macro('toIndexedById', function (string $key = 'id'): Collection {
            /** @var Collection $this */
            return $this->keyBy($key);
        });

        Collection::macro('sumMoney', function (string $attribute): int {
            /** @var Collection $this */
            return $this->sum(fn ($item) => (int) data_get($item, $attribute));
        });
    }
}

```

Call sites are now expressive:

```php
$invoices->toIndexedById();          // keyed by 'id'
$lineItems->sumMoney('amount_cents'); // domain-aware sum

```

> **IDE support tip:** Add a `/** @mixin \Illuminate\Support\Collection */` docblock to a stub class and reference it in your `_ide_helper_macros.php` so PHPStorm resolves the methods.

---

Mixins: Grouping Related Macros
-------------------------------

When you have a cluster of related methods, a mixin class keeps the service provider lean. `Collection::mixin()` reflects over every public method and registers each one as a macro.

```php
// app/Collections/MoneyCollectionMixin.php
class MoneyCollectionMixin
{
    public function sumMoney(): Closure
    {
        return function (string $attribute): int {
            return $this->sum(fn ($item) => (int) data_get($item, $attribute));
        };
    }

    public function averageMoney(): Closure
    {
        return function (string $attribute): float {
            return $this->avg(fn ($item) => (int) data_get($item, $attribute)) ?? 0.0;
        };
    }

    public function formatAsCurrency(): Closure
    {
        return function (string $attribute, string $currency = 'USD'): Collection {
            return $this->map(function ($item) use ($attribute, $currency) {
                data_set($item, $attribute, number_format(
                    data_get($item, $attribute) / 100, 2
                ) . ' ' . $currency);
                return $item;
            });
        };
    }
}

```

```php
// In the service provider:
Collection::mixin(new MoneyCollectionMixin());

```

Each public method returns a `Closure`; inside that closure `$this` is the `Collection` instance. This pattern scales cleanly — add a new mixin per bounded context.

---

Higher-Order Proxies: Chainable Magic
-------------------------------------

Laravel ships with higher-order proxies for methods like `each`, `map`, `filter`, `reject`, `every`, `first`, `flatMap`, `groupBy`, `keyBy`, `max`, `min`, `partition`, `reject`, `skipUntil`, `skipWhile`, `sortBy`, `sortByDesc`, `sum`, `takeUntil`, `takeWhile`, and `unique`. They let you call a property on the collection and chain a method name directly:

```php
$orders->each->recalculateTotals();
$users->filter->isActive()->values();
$invoices->sortByDesc->createdAt();

```

This works because `Collection::$proxies` is a public static array. You can register your own model methods into it:

```php
// In a service provider boot()
Collection::$proxies[] = 'approve';
Collection::$proxies[] = 'archive';

```

Now `$invoices->each->approve()` dispatches `approve()` on every item — no explicit closure needed.

---

Lazy Collections and Macros
---------------------------

`LazyCollection` is a separate class but also uses `Macroable`. Register macros on it independently if you need them on cursor-based result sets:

```php
use Illuminate\Support\LazyCollection;

LazyCollection::macro('filterActive', function (): LazyCollection {
    return $this->filter(fn ($item) => $item->is_active);
});

```

---

Testing Your Macros
-------------------

```php
// tests/Unit/Collections/MoneyCollectionMixinTest.php
use Illuminate\Support\Collection;

it('sums money attributes in cents', function () {
    $items = Collection::make([
        ['amount_cents' => 1000],
        ['amount_cents' => 2500],
    ]);

    expect($items->sumMoney('amount_cents'))->toBe(3500);
});

```

Register the mixin inside a `beforeEach` or rely on the full application bootstrap — either works with Pest.

---

Key Takeaways
-------------

- **Macros** are ideal for one-off domain methods; register them in a dedicated service provider.
- **Mixins** group related macros into a class, keeping the provider clean and the logic testable.
- **Higher-order proxies** eliminate boilerplate closures for single-method dispatches on collection items.
- **`LazyCollection`** has its own `Macroable` trait — register macros on it separately when working with large datasets.
- Always write unit tests for macros; they are pure functions and trivially testable with Pest.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Fextending-laravel-collections-macros-mixins-and-higher-order-proxies&text=Extending+Laravel+Collections%3A+Macros%2C+Mixins%2C+and+Higher-Order+Proxies) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Fextending-laravel-collections-macros-mixins-and-higher-order-proxies) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Can I use type hints and return types inside a Collection macro closure?        Yes, but because the closure is bound to the Collection instance at runtime, you cannot use `self` or `static` as return types. Use `Collection` explicitly, or omit the return type and rely on docblocks for IDE support. 

      Q02  Do macros registered on Collection also apply to Eloquent's Collection subclass?        No. `Illuminate\Database\Eloquent\Collection` extends the base Collection but has its own class. Register the macro on both classes, or register it only on the base class and call `parent::` methods — Eloquent Collection will inherit macros registered on the base via PHP's method resolution if the macro is not overridden. 

      Q03  Is there a performance cost to using macros over native Collection methods?        The overhead is a single `__call` dispatch and a closure invocation per macro call — negligible in practice. The real cost is always the underlying iteration, not the dispatch mechanism. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://www.msaied.com/articles) 

 [ ![Filament v5 Preview: Schema Unification, Performance Shifts, and How to Prepare](https://cdn.msaied.com/340/1a05ca68637b898b676efb66f22e627f.png) filament laravel php 

### Filament v5 Preview: Schema Unification, Performance Shifts, and How to Prepare

Filament v5 is reshaping how panels, forms, and tables are composed. This deep-dive covers the confirmed archi...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 1 Jul 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/filament-v5-preview-schema-unification-performance-shifts-and-how-to-prepare) [ ![Laravel 13: New Features, Helpers, and Practical Upgrade Notes](https://cdn.msaied.com/339/58c4fa6fe9b6d25a2dac17c621b6f4c6.png) laravel laravel-13 upgrade 

### Laravel 13: New Features, Helpers, and Practical Upgrade Notes

Laravel 13 ships with async-first defaults, a leaner bootstrapping layer, and several quality-of-life helpers....

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 1 Jul 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-13-new-features-helpers-and-practical-upgrade-notes) [ ![Laravel 12: Structured Route Files, Slim Skeletons, and the New Application Bootstrapping](https://cdn.msaied.com/337/05b39d16d0f88a5fb94d0cf74049b88b.png) laravel laravel-12 upgrade 

### Laravel 12: Structured Route Files, Slim Skeletons, and the New Application Bootstrapping

Laravel 12 ships with a leaner skeleton, first-class route file organisation, and a revised application bootst...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 1 Jul 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-12-structured-route-files-slim-skeletons-and-the-new-application-bootstrapping) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://www.msaied.com)
- [Projects](https://www.msaied.com/projects)
- [Articles](https://www.msaied.com/articles)
- [Certificates](https://www.msaied.com/certificates)
- [Contact](https://www.msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
