← Volver al blog

Macros en Laravel

2 de febrero de 2026 Job González
Macros en Laravel

Los macros en Laravel son una característica que permite extender la funcionalidad del core del framework sin modificarlo directamente. En ese sentido, comparten una idea similar a los traits: reutilizar y extender comportamiento.

Conocí el concepto de macros mientras trabajaba en una aplicación con Laravel y Livewire, donde necesitaba agregar cierta funcionalidad a un componente. Al investigar soluciones, me encontré con este mecanismo que Laravel utiliza internamente y que, curiosamente, no siempre recibe la atención que merece.

En este artículo explico qué son los macros en Laravel, cómo funcionan y en qué casos resultan especialmente útiles.

¿Qué son los Macros en Laravel?

Un macro es una manera de agregar métodos personalizados a las clases “core” de Laravel al momento de ejecución (runtime). Esto significa que puedes extender la funcionalidad de las clases de Str, Collection, Request o cualquier otra que necesites modificar que pertenezca al core Laravel.

/app/Providers/AppServiceProvider.php
// Ejemplo para obtener las iniciales de un nombre
Str::macro('initials', function ($name) {
return collect(explode(' ', $name))
->map(fn($word) => strtoupper(substr($word, 0, 1)))
->implode('');
});
/app/Http/Controller/SomeController.php
// Ahora puedes usar ese método donde quieras en tu aplicación
$initials = Str::initials('John Doe'); // regresa 'JD'

Cómo crear un macro

Sintaxis básica

Para crear un macro necesitar registrarlo en el método boot(), ya que este método se ejecuta una vez que todos los service providers han sido registrados, por ejemplo View, Blade, Route etc. y ahí es el momento perfecto para agregar tu código personalizado.

/app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Str;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Str::macro('initials', function ($name) {
return collect(explode(' ', $name))
->map(fn($word) => strtoupper(substr($word, 0, 1)))
->implode('');
});
}
}

Macros en la clase Collections

Las colecciones son ideales para generar macros personalizados:

/app/Providers/AppServiceProvider.php
// Agrupar por dominio
Collection::macro('groupByDomain', function () {
return $this->groupBy(function ($item) {
return parse_url($item['url'], PHP_URL_HOST);
});
});
// Seleccionar opciones de la colección
Collection::macro('toSelectOptions', function ($valueField, $labelField) {
return $this->mapWithKeys(function ($item) use ($valueField, $labelField) {
return [$item[$valueField] => $item[$labelField]];
})->toArray();
});
/app/Http/Controller/SomeController.php
// Uso
$urls = collect([
['url' => 'https://example.com/page1', 'title' => 'Page 1'],
['url' => 'https://example.com/page2', 'title' => 'Page 2'],
['url' => 'https://another.com/page1', 'title' => 'Another Page'],
]);
$grouped = $urls->groupByDomain();
/* Resultado esperado:
[
'example.com' => [
['url' => 'https://example.com/page1', 'title' => 'Page 1'],
['url' => 'https://example.com/page2', 'title' => 'Page 2'],
],
'another.com' => [
['url' => 'https://another.com/page1', 'title' => 'Another Page'],
],
]
*/
$options = $urls->toSelectOptions('url', 'title');
/* Resultado esperado:
[
'https://example.com/page1' => 'Page 1',
'https://example.com/page2' => 'Page 2',
'https://another.com/page1' => 'Another Page',
]
*/

Macros en la clase Request

Agregar funciones útiles a la clase Request con métodos de validación y extracción de datos.

  • Validar si la petición es Ajax
/app/Providers/AppServiceProvider.php
// Valida si la petición es Ajax
Request::macro('isAjax', function () {
return $this->headers->get('X-Requested-With') === 'XMLHttpRequest';
});
// ⚠️ Nota: este macro es solo ilustrativo, ya que Laravel incluye `$request->ajax()` y `$request->expectsJson()`
/app/Http/Controller/SomeController.php
// Uso
if ($request->isAjax()) {
return response()->json(['message' => 'Ajax request detected']);
}

  • Obtener información en específica desde un json
/app/Providers/AppServiceProvider.php
// Obtener la api key de la petición desde el header, si no se encuentra recupera el valor del body "api_key"
Request::macro('getApiKey', function () {
return $this->header('X-API-Key') ?? $this->query('api_key');
});
/app/Http/Controller/SomeController.php
// Uso
$apiKey = $request->getApiKey();

  • Validar IPs
/app/Providers/AppServiceProvider.php
// Valida si la petición (request) esta dentro del listado de IPs permitidas
Request::macro('validateIp', function ($allowedIps) {
return in_array($this->ip(), $allowedIps);
});
/app/Http/Controller/SomeController.php
// Uso
if (!$request->validateIp(['127.0.0.1', '192.168.1.1'])) {
abort(403);
}

Uso de macros en Livewire

Como mencionaba al inicio, conocí el concepto de Macros en Laravel ya que en una aplicación de Laravel con Livewire estaba implementando un componente para arrojar notificaciones en la aplicación y encontré este artículo de Fly.io donde se mencionaba el concepto de macros, lo que me llevó a investigarlos con más detalle. En si la implementación del macro es la siguiente:

/app/Providers/AppServiceProvider.php
// Agregar método notify a la clase Componente de Livewire
Component::macro('notify', function ($message) {
// $this hace referencia a la clase del componente Liveware y no a la clase AppServiceProvider
// Esto permite crear APIs internas reutilizables entre componentes
$this->dispatch('notify', $message);
});
/app/Livewire/My/ClickyButton.blade.php
namespace App\Http\Livewire;
use Livewire\Component;
class ClickyButton extends Component
{
public function tellme()
{
$messages = [
"Some", "Random", "Messages"
];
// Uso del macro
$this->notify($messages[array_rand($messages)]);
}
}

Clases Macroables

No todas las clases en Laravel pueden ser extendidas por medio de macros. Para poder extenderla la clase debe usar el trait Illuminate\Support\Traits\Macroable

Las clases macroables más comunes son:

  • Str
  • Collection
  • Request
  • Response
  • Router
  • Validator
  • Cache
  • File

Para el caso de Livewire, podemos ver en la clase Component que está usando la clase Macroable en este archivo, por eso es que anteriormente pudimos agregar un macro a la clase Component de Livewire.

Macros Condicionales

Es posible registrar macros de forma condicional, por ejemplo, si estamos ejecutando la aplicación en un ambiente local se registrará el macro debug:

/app/Providers/AppServiceProvider.php
public function boot()
{
if (app()->environment('local')) {
Str::macro('debug', function ($string) {
return "DEBUG: {$string}";
});
}
}

Recomendaciones prácticas

1. Tipa los parámetros y valor de retorno

Como si de una función se tratase, los macros aceptan parámetros y la posibilidad de tiparlos, así como al valor de retorno.

Laravel no impone tipado en los parámetros, pero PHP moderno lo permite y es recomendable usarlo.

/app/Providers/AppServiceProvider.php
Collection::macro('paginate', function (int $perPage = 15, ?int $page = null): LengthAwarePaginator {
$page = $page ?: request()->get('page', 1);
$total = $this->count();
return new LengthAwarePaginator(
$this->forPage($page, $perPage)->values(),
$total,
$perPage,
$page,
['path' => request()->url()]
);
});

2. Organiza tus Macros

Crea un service provider dedicado por cada tipo distinto de macro:

app/Providers/StringMacrosServiceProvider.php
class StringMacrosServiceProvider extends ServiceProvider
{
public function boot()
{
Str::macro('toSlug', function ($string) {
return Str::slug($string);
});
Str::macro('shorten', function ($string, $length = 50) {
return strlen($string) > $length
? substr($string, 0, $length) . '...'
: $string;
});
}
}

3. Documenta tus Macros

No escatimes en documentar tus macros, si trabajas con más personas te lo agradecerán tanto ellos como tu yo del futuro.

/app/Providers/AppServiceProvider.php
/**
* Convert a string to URL-friendly slug format
*
* @param string $string
* @return string
*/
Str::macro('toSlug', function ($string) {
return Str::slug($string);
});

4. Realiza testing en tus Macros

Realiza testing a tus macros, por más sencillo que parezca es una buena práctica.

/tests/Unit/Support/StrMacrosTest.php
class StringMacrosTest extends TestCase
{
public function test_to_slug_macro()
{
$this->assertEquals('hello-world', Str::toSlug('Hello World'));
$this->assertEquals('laravel-is-awesome', Str::toSlug('Laravel Is Awesome!'));
}
}

5. Evitar conflictos

Puedes verificar si un macro ya ha sido registrado antes de registrarlo:

/app/Providers/AppServiceProvider.php
if (!Collection::hasMacro('someMacro')) {
Collection::macro('someMacro', function () {
// Lógica de tu macro...
});
}

Usos prácticos

1. Macros en la clase Response

Utilidad para responder con un json de manera más sencilla.

/app/Providers/AppServiceProvider.php
Response::macro('api', function ($data = null, $message = 'Success', $status = 200) {
return response()->json([
'success' => $status < 400,
'message' => $message,
'data' => $data,
], $status);
});
/app/Http/Controller/SomeController.php
// Uso
return Response::api($user, 'User created successfully', 201);

2. Macro para el sistema de archivos

Utilidad para asegurar que un directorio existe.

File::macro('ensureDirectoryExists', function ($path) {
if (!File::exists($path)) {
File::makeDirectory($path, 0755, true);
}
return $path;
});

Conclusion

Los macros de Laravel son una excelente forma de extender el core del framework a tu necesidad, permitiéndote:

  • Agregar funcionalidad personalizada a las clases core de Laravel
  • Crear métodos específicos que se sientan más natural al usarse
  • Reducir la duplicidad de código en tu aplicación
  • Mejorar la redacción de tu lógica de negocio en tu aplicación

Como con cualquier mecanismo de extensión, la clave está en no abusar de ellos y documentarlos correctamente para que su uso sea claro tanto para tu equipo como para tu yo del futuro.

laravel php utilidad