Laravel Macros, Mixins &amp; Custom Collections | 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)    Laravel Macros, Mixins, and Custom Collection Methods That Actually Ship        On this page       1. [  Laravel Macros, Mixins, and Custom Collection Methods That Actually Ship ](#laravel-macros-mixins-and-custom-collection-methods-that-actually-ship)
2. [  How Macroable Works Under the Hood ](#how-codemacroablecode-works-under-the-hood)
3. [  Registering Macros in a Service Provider ](#registering-macros-in-a-service-provider)
4. [  Mixins: Sharing Many Methods at Once ](#mixins-sharing-many-methods-at-once)
5. [  Octane Safety: Static State Is Shared Across Requests ](#octane-safety-static-state-is-shared-across-requests)
6. [  IDE Support with @mixin and Laravel IDE Helper ](#ide-support-with-code-at-mixincode-and-laravel-ide-helper)
7. [  Extending Beyond Collection ](#extending-beyond-collection)
8. [  Takeaways ](#takeaways)

  ![Laravel Macros, Mixins, and Custom Collection Methods That Actually Ship](https://cdn.msaied.com/185/fd4edfcd494ecfe6c55223beff0d9d79.png)

  #laravel   #macros   #collections   #php  

 Laravel Macros, Mixins, and Custom Collection Methods That Actually Ship 
==========================================================================

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

       Table of contents

1. [  01   Laravel Macros, Mixins, and Custom Collection Methods That Actually Ship  ](#laravel-macros-mixins-and-custom-collection-methods-that-actually-ship)
2. [  02   How Macroable Works Under the Hood  ](#how-codemacroablecode-works-under-the-hood)
3. [  03   Registering Macros in a Service Provider  ](#registering-macros-in-a-service-provider)
4. [  04   Mixins: Sharing Many Methods at Once  ](#mixins-sharing-many-methods-at-once)
5. [  05   Octane Safety: Static State Is Shared Across Requests  ](#octane-safety-static-state-is-shared-across-requests)
6. [  06   IDE Support with @mixin and Laravel IDE Helper  ](#ide-support-with-code-at-mixincode-and-laravel-ide-helper)
7. [  07   Extending Beyond Collection  ](#extending-beyond-collection)
8. [  08   Takeaways  ](#takeaways)

 Laravel Macros, Mixins, and Custom Collection Methods That Actually Ship
------------------------------------------------------------------------

The `Macroable` trait is one of Laravel's quieter superpowers. Used well, it lets you extend core classes without forking the framework. Used carelessly, it produces invisible globals that confuse teammates and break under Octane. This article covers the practical patterns that survive production.

---

### How `Macroable` Works Under the Hood

Any class that uses `Illuminate\Support\Traits\Macroable` stores closures in a static `$macros` array. When you call an unknown method, `__call` (or `__callStatic`) checks that array and invokes the closure, binding `$this` to the current instance.

```php
// Simplified internals
public static function macro(string $name, callable $macro): void
{
    static::$macros[$name] = $macro;
}

public function __call(string $method, array $parameters)
{
    if (isset(static::$macros[$method])) {
        return Closure::bind(static::$macros[$method], $this, static::class)(...$parameters);
    }
    throw new BadMethodCallException(...);
}

```

Because `$macros` is **static**, macros registered in a service provider persist for the lifetime of the PHP process — which is exactly what you want in a traditional FPM setup, and exactly what you must reason about under Octane.

---

### Registering Macros in a Service Provider

Always register in `boot()`, never in `register()`. The framework classes you're extending may not be bound yet during `register()`.

```php
namespace App\Providers;

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

class CollectionMacroServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Collection::macro('filterMap', function (callable $callback): Collection {
            /** @var Collection $this */
            return $this->map($callback)->filter()->values();
        });

        Collection::macro('groupByFirst', function (string $key): Collection {
            /** @var Collection $this */
            return $this->keyBy(fn ($item) => data_get($item, $key));
        });
    }
}

```

Register the provider in `bootstrap/providers.php` (Laravel 11+) or `config/app.php`.

---

### Mixins: Sharing Many Methods at Once

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 must return a `Closure`.

```php
namespace App\Support\Mixins;

use Illuminate\Support\Collection;

class CollectionMixin
{
    public function toAssoc(): \Closure
    {
        return function (string $keyField, string $valueField): Collection {
            /** @var Collection $this */
            return $this->mapWithKeys(
                fn ($item) => [data_get($item, $keyField) => data_get($item, $valueField)]
            );
        };
    }

    public function chunkWhile(): \Closure
    {
        // Laravel already has chunkWhile; this is illustrative
        return function (callable $callback): Collection {
            /** @var Collection $this */
            $chunks = [];
            $chunk = [];
            foreach ($this->items as $item) {
                if (empty($chunk) || $callback($item, end($chunk))) {
                    $chunk[] = $item;
                } else {
                    $chunks[] = $chunk;
                    $chunk = [$item];
                }
            }
            if ($chunk) {
                $chunks[] = $chunk;
            }
            return new static($chunks);
        };
    }
}

```

Register the mixin in one call:

```php
Collection::mixin(new CollectionMixin());

```

---

### Octane Safety: Static State Is Shared Across Requests

Because macros live in static arrays, they are registered **once** when the worker boots and remain for every subsequent request. This is fine — registration is idempotent. The danger is registering macros **inside a request cycle** (e.g., in a controller or middleware), which can cause subtle state leakage if the closure captures request-scoped objects.

**Rule:** register macros only in service providers, never inside request-handling code.

---

### IDE Support with `@mixin` and Laravel IDE Helper

Without hints, PhpStorm treats macro calls as errors. Two approaches:

1. Add a `/** @mixin CollectionMixin */` docblock to a stub file that `ide-helper` picks up.
2. Use `barryvdh/laravel-ide-helper` with `php artisan ide-helper:generate` — it reads registered macros and writes stubs automatically.

---

### Extending Beyond Collection

The same pattern works on `Request`, `Builder` (query builder), `Carbon`, and `Response`:

```php
use Illuminate\Http\Request;

Request::macro('isHtmx', function (): bool {
    /** @var Request $this */
    return $this->hasHeader('HX-Request');
});

// Usage in a controller:
if ($request->isHtmx()) {
    return view('partials.table');
}

```

Extending `Illuminate\Database\Query\Builder` follows the same pattern but be careful: the query builder is instantiated per query, so closures must not assume singleton state.

---

### Takeaways

- Register macros in `boot()` inside a dedicated service provider — never inside request handlers.
- Use **mixins** when you have more than two or three related methods; it keeps the provider clean.
- Closures in macros bind `$this` to the host instance, so you get full access to internal properties.
- Under Octane, static macro registration is safe because it happens once at worker boot.
- Add IDE stubs via `ide-helper` or `@mixin` docblocks so teammates get autocomplete.
- Extending `Request` with domain-specific helpers (e.g., `isHtmx()`, `tenantId()`) is one of the highest-value uses of macros in a real application.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Flaravel-macros-mixins-and-custom-collection-methods-that-actually-ship&text=Laravel+Macros%2C+Mixins%2C+and+Custom+Collection+Methods+That+Actually+Ship) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Flaravel-macros-mixins-and-custom-collection-methods-that-actually-ship) 

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

  3 questions  

     Q01  Can I override an existing Collection method with a macro?        No. `__call` is only invoked for methods that do not exist natively on the class. If a method is already defined, the macro is silently ignored. Use a subclass or a decorator if you need to override native behaviour. 

      Q02  Is it safe to type-hint macro return values in strict PHP 8.3 codebases?        Macros are resolved at runtime, so PHP's static analyser cannot infer their return types. Annotate the closure's return type explicitly and add a `@method` docblock to a stub class so PHPStan or Psalm can follow the type through call sites. 

      Q03  Should every team utility live as a macro, or is there a better place?        Prefer macros for methods that genuinely feel native to the extended class (e.g., a Collection helper that reads like a built-in). For domain logic, a dedicated service or action class is clearer and easier to test in isolation. 

  Continue reading

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

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

 [ ![Laravel Telescope Alternatives: Building a Lightweight Request Inspector with Middleware](https://cdn.msaied.com/216/9b6d240010b80483f072902dafcd216c.png) laravel middleware debugging 

### Laravel Telescope Alternatives: Building a Lightweight Request Inspector with Middleware

Telescope is powerful but heavy for production. Learn how to build a focused, low-overhead request inspector u...

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

 16 Jun 2026     1 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-telescope-alternatives-building-a-lightweight-request-inspector-with-middleware) [ ![RAG Pipelines in Laravel: Chunking, Embedding, and Retrieval with pgvector](https://cdn.msaied.com/215/e037e13535aa77822f879ee829ec3f68.png) laravel ai pgvector 

### RAG Pipelines in Laravel: Chunking, Embedding, and Retrieval with pgvector

Build a production-ready Retrieval-Augmented Generation pipeline in Laravel using pgvector, OpenAI embeddings,...

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

 16 Jun 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/rag-pipelines-in-laravel-chunking-embedding-and-retrieval-with-pgvector) [ ![Laravel Pest: Architecture Tests, Mutation Testing, and Type Coverage in CI](https://cdn.msaied.com/214/0d4822fa8ee1765d0689e387dd849d92.png) laravel pest testing 

### Laravel Pest: Architecture Tests, Mutation Testing, and Type Coverage in CI

Go beyond feature tests. Learn how to enforce architectural rules, catch logic gaps with mutation testing, and...

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

 16 Jun 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-pest-architecture-tests-mutation-testing-and-type-coverage-in-ci) 

   [  ![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)
