Laravel Macros, Mixins &amp; Custom Collections | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Macros, Mixins, and Custom Collection Methods in Laravel

 Macros, Mixins, and Custom Collection Methods in Laravel
=========================================================

 Learn how to extend Laravel's core classes with macros, mixins, and custom Collection methods — keeping your codebase expressive without forking the framework.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 13 Sep 2026 · Updated 13 Sep 2026 · 4 min read

ShareCopy linkCopied

 ![Macros, Mixins, and Custom Collection Methods in Laravel](https://cdn.msaied.com/663/b8e39b17d427358aa43b5c3e8c1be908.png) 

  On this page +1. [Extending Laravel Without Forking It](#extending-laravel-without-forking-it)
2. [How Macroable Works](#how-codemacroablecode-works)
3. [Registering Macros the Right Way](#registering-macros-the-right-way)
4. [Mixins: Grouping Related Macros](#mixins-grouping-related-macros)
5. [IDE Support: Don't Skip This](#ide-support-dont-skip-this)
6. [Beyond Collections: Other Macroable Classes](#beyond-collections-other-macroable-classes)
7. [When Not to Use Macros](#when-not-to-use-macros)
8. [Takeaways](#takeaways)

 Extending Laravel Without Forking It
------------------------------------

Laravel ships with a `Macroable` trait that lets you bolt new behaviour onto core classes at runtime. Used well, it keeps domain language inside your codebase rather than scattered across helper files. Used carelessly, it turns a clean project into a maze of invisible methods. This article covers the mechanics, the guardrails, and the patterns that actually hold up at scale.

---

How `Macroable` Works
---------------------

Any class that uses `Illuminate\Support\Traits\Macroable` gains two static methods: `macro()` and `mixin()`. At call time, `__call` and `__callStatic` proxy to the registered closure.

```php
use Illuminate\Support\Collection;

Collection::macro('toAssoc', function (string $key, string $value): Collection {
    /** @var Collection $this */
    return $this->mapWithKeys(fn ($item) => [$item[$key] => $item[$value]]);
});

$result = collect([
    ['code' => 'USD', 'label' => 'US Dollar'],
    ['code' => 'EUR', 'label' => 'Euro'],
])->toAssoc('code', 'label');
// ['USD' => 'US Dollar', 'EUR' => 'Euro']

```

Inside the closure, `$this` is bound to the current collection instance, so you have full access to `$this->items` and every existing method.

---

Registering Macros the Right Way
--------------------------------

Never register macros in a controller or a model. Always use a **service provider** so the macro is available on every request before any consumer needs it.

```php
// app/Providers/CollectionMacroServiceProvider.php

namespace App\Providers;

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

class CollectionMacroServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Collection::macro('second', function (): mixed {
            return $this->skip(1)->first();
        });

        Collection::macro('mapToModel', function (string $class): Collection {
            return $this->map(fn ($data) => new $class($data));
        });
    }
}

```

Add it to `bootstrap/providers.php` (Laravel 11+) or `config/app.php` providers array.

---

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

When you have a family of related methods, a **mixin class** is cleaner than a long list of `macro()` calls. Each public method on the mixin class returns a closure that becomes a macro.

```php
// app/Mixins/CollectionCurrencyMixin.php

namespace App\Mixins;

use Illuminate\Support\Collection;

class CollectionCurrencyMixin
{
    public function sumMoney(): \Closure
    {
        return function (string $field, int $scale = 2): string {
            /** @var Collection $this */
            $total = $this->sum(fn ($item) => (int) round($item[$field] * (10 ** $scale)));
            return number_format($total / (10 ** $scale), $scale);
        };
    }

    public function formatAmounts(): \Closure
    {
        return function (string $field, string $currency = 'USD'): Collection {
            /** @var Collection $this */
            return $this->map(function ($item) use ($field, $currency) {
                $item[$field . '_formatted'] = $currency . ' ' . number_format($item[$field], 2);
                return $item;
            });
        };
    }
}

```

```php
// In your service provider boot()
Collection::mixin(new CollectionCurrencyMixin());

```

---

IDE Support: Don't Skip This
----------------------------

Macros are invisible to static analysis. Add a `@mixin` docblock or generate an `_ide_helper_macros.php` file with `barryvdh/laravel-ide-helper`. For Psalm/PHPStan, create a stub:

```php
// stubs/CollectionMacros.php  (excluded from autoload)

/** @mixin \Illuminate\Support\Collection */
class CollectionMacroStub
{
    public function toAssoc(string $key, string $value): \Illuminate\Support\Collection {}
    public function second(): mixed {}
}

```

Point your `phpstan.neon` at the stubs directory. Now your CI pipeline catches misuse.

---

Beyond Collections: Other Macroable Classes
-------------------------------------------

`Request`, `Response`, `Builder` (query builder), `Router`, `Str`, `Arr`, and `Carbon` (via `CarbonMixin`) all support macros. A practical example — adding a typed helper to the query builder:

```php
use Illuminate\Database\Query\Builder;

Builder::macro('whereUuid', function (string $column, string $uuid): Builder {
    /** @var Builder $this */
    return $this->where($column, '=', $uuid);
});

// Usage
User::query()->whereUuid('id', $request->uuid)->firstOrFail();

```

---

When Not to Use Macros
----------------------

- **Complex logic with dependencies** — inject a service instead; closures can't receive constructor injection cleanly.
- **Methods that need to be overridden per model** — use a custom base model or a trait.
- **Anything that should be tested in isolation** — macros are global state; prefer explicit classes for domain-critical logic.

---

Takeaways
---------

- Register all macros in a dedicated service provider, never inline.
- Use mixin classes to group related macros and keep providers readable.
- Add IDE stubs or `@mixin` annotations — macros without static analysis support create invisible debt.
- `Macroable` is available on `Request`, `Builder`, `Str`, `Router`, and more, not just `Collection`.
- Macros are global state; reserve them for genuinely cross-cutting, stateless helpers.

- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [collections](https://www.msaied.com/public/articles?search=collections)
- [macros](https://www.msaied.com/public/articles?search=macros)
- [php](https://www.msaied.com/public/articles?search=php)

 Frequently asked questions 
---------------------------

  Can I use dependency injection inside a Collection macro closure?Not directly via constructor injection. You can call `app(MyService::class)` inside the closure, but if the logic is complex enough to need a service, extract it into a dedicated class and call that from the macro instead.

   Do macros survive between Octane requests?Yes — macros are registered on the class itself (stored in a static array), so they persist across requests in long-running processes like Octane. Register them once in a service provider and they remain available for the lifetime of the worker.

   What is the difference between a macro and a mixin in Laravel?A macro registers a single named closure on a Macroable class. A mixin registers all public methods of a class as macros in one call, which is cleaner when you have a family of related helpers to add.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

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

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleModular Monolith in Laravel: Enforcing Bounded Contexts with Module Service Providers](https://www.msaied.com/public/articles/modular-monolith-in-laravel-enforcing-bounded-contexts-with-module-service-providers) [Next articleFilament v4 at Scale: Multi-Panel Auth, Custom Panels, and Table Query Tuning](https://www.msaied.com/public/articles/filament-v4-at-scale-multi-panel-auth-custom-panels-and-table-query-tuning)  

   On this page
-------------

1. [Extending Laravel Without Forking It](#extending-laravel-without-forking-it)
2. [How Macroable Works](#how-codemacroablecode-works)
3. [Registering Macros the Right Way](#registering-macros-the-right-way)
4. [Mixins: Grouping Related Macros](#mixins-grouping-related-macros)
5. [IDE Support: Don't Skip This](#ide-support-dont-skip-this)
6. [Beyond Collections: Other Macroable Classes](#beyond-collections-other-macroable-classes)
7. [When Not to Use Macros](#when-not-to-use-macros)
8. [Takeaways](#takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
