If you check the Laravel codebase I’m sure that you can observe that Laravel makes use of traits.

There is one trait in the source code that pulls my attention. I’m talking about the Macroable trait.

In case you don’t know, you can define custom responses using macros.

For example, you can extend the Response class to do something new in your projects like:

Response::macro('caps', function ($value) {

return Response::make(strtoupper($value));

});

And use it like this:

return response()->caps('foo');

The purpose of this trait is to extend (not in an OOP sense) a class at run-time. This way, you can add behavior without editing the original class source code.

It might be bad that someone can access to your classes and add behaviors by wrecking everything. But if you use it with a grain of salt, it can be a powerful way to give to your consumers a choice to build upon your code.

If you develop packages think about releasing your extendable components as macroable.

How Does Everything Work?

When using this trait your class will “inherit” a static $macros array property.

The macro method assigns to the $macros array the given callable.

public static function macro($name, callable $macro)

{

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

}

But when this call occurs? The PHP engine triggers __call() when invoking inaccessible methods in an object context.

So when we do something like:

return response()->caps('foo');

The engine executes this magic method:

public function __call($method, $parameters)

{

if (! static::hasMacro($method)) {

throw new BadMethodCallException("Method {$method} does not exist.");

}



if (static::$macros[$method] instanceof Closure) {

return call_user_func_array(static::$macros[$method]->bindTo($this, static::class), $parameters);

}



return call_user_func_array(static::$macros[$method], $parameters);

}

The logic of this method is:

If $macros do not have the called $method throw an exception.

do not have the called throw an exception. If $macros do have the called $method and it’s a Closure, invoke this closure binding $this with the class scope and the provided $parameters .

do have the called and it’s a Closure, invoke this closure binding with the class scope and the provided . If $macros do have the called $method and it’s callable, invoke it with the provided $parameters.

The same happens for the __callStatic magic method. And due to how PHP works you can also access inner methods or properties while defining a macro.