Macroable — это трейт (Illuminate\Support\Traits\Macroable), который позволяет динамически добавлять методы в классы во время выполнения приложения.
Проще говоря:
ты можешь взять уже существующий класс Laravel (или свой) и дописать в него новые методы, не меняя сам класс.
Это очень мощный приём, особенно когда:
- нельзя или не хочется наследоваться
- нужно расширить функциональность фреймворка
- хочется писать чистый, читаемый код без хелперов по всему проекту
Простая аналогия
Представь, что у тебя есть класс Collection.
Обычно ты пишешь:
collect($users)->filter(...)->map(...)
А теперь представь, что тебе нужен метод ->active().
Вместо:
collect($users)->filter(fn ($u) => $u->active);
Ты хочешь:
collect($users)->active();
Вот тут и появляется Macroable.
Как работает Macroable внутри
Если заглянуть под капот, то:
- макросы хранятся в статическом массиве
- при вызове метода Laravel проверяет:
«А нет ли такого макроса?»
Если есть — он вызывается как обычный метод объекта.
Пример: добавляем макрос в Collection
1. Добавляем макрос
Обычно это делают в AppServiceProvider:
use Illuminate\Support\Collection;
public function boot()
{
Collection::macro('active', function () {
return $this->filter(fn ($item) => $item->active);
});
}
2. Используем
$users = User::all()->active();
✨ Чисто, красиво, читаемо.
Macroable ≠ Хелперы
Очень важный момент.
Плохо:
active_users($users);
Хорошо:
$users->active();
Почему?
- читается как естественный язык
- не засоряет глобальное пространство функций
- легко найти через IDE
- логически относится к объекту
Какие классы в Laravel уже Macroable
Laravel активно использует этот трейт. Вот самые популярные:
CollectionStrResponseRequestRouteBuilder(Eloquent и Query Builder)Carbon
Пример: макрос для Str
use Illuminate\Support\Str;
Str::macro('telegramEscape', function (string $text) {
return preg_replace('/([_*\[\]()~`>#+\-=|{}.!])/', '\\\\$1', $text);
});
Использование:
Str::telegramEscape($message);
Макросы для Eloquent Builder
Очень мощная тема.
Пример: scope без scope
use Illuminate\Database\Eloquent\Builder;
Builder::macro('active', function () {
return $this->where('active', true);
});
Использование:
User::query()->active()->get();
⚠️ И да — это альтернатива локальным scope, но не замена.
Макросы хороши, когда логика общая для многих моделей.
Макросы с аргументами
Collection::macro('paginate', function ($perPage = 15) {
$page = request('page', 1);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$this->count(),
$perPage,
$page
);
});
$items->paginate(20);
Когда Macroable — это хорошая идея
Используй макросы, если:
- логика общая
- метод логично относится к объекту
- не хочется наследования
- нужно расширить фреймворк
Когда НЕ стоит использовать Macroable
Не лучший выбор, если:
- логика специфична для одной модели
- метод нужен в одном месте
- ты прячешь бизнес-логику слишком глубоко
- макрос зависит от контекста (auth, request, session)
Где хранить макросы
Лучшие варианты:
AppServiceProvider- отдельный сервис-провайдер:
app/Providers/MacroServiceProvider.php - по доменам:
app/Macros/CollectionMacros.php app/Macros/StrMacros.php
И регистрировать их аккуратно и централизованно.
Типизация и IDE
Laravel умеет @mixin и @method — не игнорируй это.
/**
* @method static Collection active()
*/
class Collection {}
Или через IDE helper — тогда автокомплит будет идеальным.
Итог
Macroable — это один из самых недооценённых инструментов Laravel.
Он позволяет:
- писать выразительный код
- расширять фреймворк без костылей
- избегать хелперов и лишнего наследования
Если использовать его осознанно — код становится чище, короче и понятнее.