---
title: Laravel Macros Postmortem
description: "How Laravel macros add methods to a class at runtime with the Macroable trait, with examples and where to register them in your app."
keywords:
 - Laravel
 - Macros
 - Laravel Macros Postmortem
canonical_url: "/laravel-macros-postmortem/"
date_published: "2021-01-20"
date_modified: "2026-10-08"
type: post
author: Rohan Jalil
---

# Laravel Macros Postmortem


Laravel gives you the ability to add methods to a class at runtime by using the [Macroable (Illuminate\Support\Traits\Macroable)](https://laravel.com/api/master/Illuminate/Support/Traits/Macroable.html) [Trait](https://www.php.net/manual/en/language.oop5.traits.php). You need to use the [Macroable](https://laravel.com/api/master/Illuminate/Support/Traits/Macroable.html) trait inside the class in which you want to add methods at run time.


Here is an [example](https://laravel.com/docs/13.x/collections#extending-collections) from the Laravel Documentation. The following code adds a toUpper method to the Collection class:


```
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

Collection::macro('toUpper', function () {
 return $this->map(function ($value) {
 return Str::upper($value);
 });
});

$collection = collect(['first', 'second']);

$upper = $collection->toUpper();

// ['FIRST', 'SECOND']
```


---


## How to Register Your Macros?


Laravel’s Macroable trait offers 2 ways to register your macros.


1. Using `Macroable::macro($name, $macro)` method.
2. Using `Macroable::mixin($mixin, $replace)` method.


---


## How the Magic Stuff Works?


For the magic stuff to work, you need to have [Magic Methods](https://www.php.net/manual/en/language.oop5.magic.php). Macros magic is based on two magic methods provided by PHP: [`__call()`](https://www.php.net/manual/en/language.oop5.overloading.php#object.call) and [`__callStatic()`](https://www.php.net/manual/en/language.oop5.overloading.php#object.callstatic).


How it all works behind the scenes is that if you call a method on a class object which doesn’t exist, and you have defined the `__call()` magic method, control will go to this method. Here you can capture the request and perform any task you want, for example log it and throw an exception.


Laravel uses this concept very intelligently and neatly. Laravel has defined these magic methods inside the Macroable trait. First the Macroable trait is used inside a class where we want to add dynamic methods.


```
use Illuminate\Support\Traits\Macroable;

class JsonResponse extends BaseJsonResponse
{
 use ResponseTrait, Macroable {
 Macroable::__call as macroCall;
 }
}
```


Then we register our method by calling the macro static method. For example, let’s add functionality in our Laravel Response class to capitalize a value. We can do that with the following piece of code, an example taken from the Laravel Documentation.


```
Response::macro('caps', function ($value) {
 return Response::make(strtoupper($value));
});
```


Implementation of the macro function is pretty straightforward. It maintains a mapping of the name of the newly added function and the callback for it.


```
/**
 * Register a custom macro.
 *
 * @param string $name
 * @param object|callable $macro
 * @return void
 */
public static function macro($name, $macro)
{
 static::$macros[$name] = $macro;
}
```


After registering your macro, it is time to call it!


Once you call your registered macro, for example `Response::caps('laravel')`, the request flow will be the following:


- The call first goes to the Response class, and the PHP engine checks for the definition of the called method. In our case it checks for a `caps` function definition in the Response class (`Illuminate/Routing/ResponseFactory`).
- If the method is found, it is executed. Otherwise the PHP engine checks for the `__call()` and `__callStatic()` magic methods, depending on whether the function was called statically or not.
- In our case, the Response class (`Illuminate/Routing/ResponseFactory`) does not have a `caps` method defined, so the PHP engine forwards control to either `__call()` or `__callStatic()` (depending on the call type) defined in the Macroable trait. Here we first check whether the called function is registered as a macro. If not, a **BadMethodCallException** is thrown. If it is, we bind the macro callback to the class reference and execute it.


```
/**
 * Dynamically handle calls to the class.
 *
 * @param string $method
 * @param array $parameters
 * @return mixed
 *
 * @throws \BadMethodCallException
 */
public static function __callStatic($method, $parameters)
{
 if (! static::hasMacro($method)) {
 throw new BadMethodCallException(sprintf(
 'Method %s::%s does not exist.', static::class, $method
 ));
 }

 $macro = static::$macros[$method];

 if ($macro instanceof Closure) {
 return call_user_func_array(Closure::bind($macro, null, static::class), $parameters);
 }

 return $macro(...$parameters);
}

/**
 * Dynamically handle calls to the class.
 *
 * @param string $method
 * @param array $parameters
 * @return mixed
 *
 * @throws \BadMethodCallException
 */
public function __call($method, $parameters)
{
 if (! static::hasMacro($method)) {
 throw new BadMethodCallException(sprintf(
 'Method %s::%s does not exist.', static::class, $method
 ));
 }

 $macro = static::$macros[$method];

 if ($macro instanceof Closure) {
 return call_user_func_array($macro->bindTo($this, static::class), $parameters);
 }

 return $macro(...$parameters);
}
```


---


## What if I Want to Define Multiple Macros?


Laravel to the rescue again! You can define multiple macros at once using the `Macroable::mixin($mixin, $replace)` method. The `$mixin` argument is a class object whose methods return callables.


```
class MixinClass
{
 public function firstMixin(): Closure
 {
 return function () {
 return 'I am first Mixin!';
 };
 }

 public function secondMixin(): Closure
 {
 return function () {
 return 'I am Second Mixin!';
 };
 }
}

$mixin = new MixinClass();

$macroClass->mixin($mixin);

$macroClass->firstMixin(); // I am first Mixin!

$macroClass->secondMixin(); // I am Second Mixin!
```


---


## Scope of Macros


One important thing to note about macros is that they are bound to the class scope in which the Macroable trait is used, not the scope from which they are registered. For example, let’s add a `whoami` method to our Laravel Response class ([`Illuminate/Routing/ResponseFactory`](https://laravel.com/api/master/Illuminate/Routing/ResponseFactory.html)) to check the scope of **$this**.


```
class AppServiceProvider extends ServiceProvider
{
 /**
 * Bootstrap any application services.
 *
 * @return void
 */
 public function boot()
 {
 Response::macro('whoAmi', function () {
 return get_class($this);
 });
 }
}
```


When we call this in our test route, we get a result of **Illuminate\Routing\ResponseFactory**, not **AppServiceProvider**.


```
Route::get('test', function () {
 return Illuminate\Support\Facades\Response::whoAmi();
});

// Output is Illuminate\Routing\ResponseFactory
```


The secret behind this is the [`bindTo`](https://www.php.net/manual/en/closure.bindto.php) method of the [PHP Closure class](https://www.php.net/manual/en/class.closure.php). The `bindTo` method binds the callback to the called class scope. Inside your macro callback, `$this` is the called class scope, and you can access other accessible methods and attributes.


---


## Where Can Macros Be Defined?


You can define macros inside Laravel’s [Service Providers](https://laravel.com/docs/13.x/providers). `App\Providers\AppServiceProvider`‘s `boot()` method is a good starting point. If you have many macros in your application, the recommended approach is to create your own Service Provider class for macros and register it in `config/app.php`.


---


If you found this useful, the same walk-down-to-the-SQL treatment is applied to Laravel 13’s new semantic search in the [Laravel Vector Search Postmortem](/laravel-vector-search-postmortem/).