wp-starter/macroable
Lightweight Macroable trait for PHP/Laravel-style macros. Add runtime methods to your classes, register macros and mixins, and call them like native methods—useful for extending objects without inheritance or boilerplate.
macroable package extends PHP’s Macroable trait (common in Laravel’s ecosystem) to enable dynamic method injection at runtime. This aligns well with Laravel’s fluent, expressive syntax and service container patterns, where macros are already used (e.g., Str::macro(), Collection::macro()).Macroable::extend()).Stringable, Collection, QueryBuilder).Macroable testing helpers (e.g., Macroable::fake()).__call() magic methods, which can impact performance in tight loops. Benchmark critical paths.User::macro('findByEmail', ...) vs. User::findByEmail()).debugbacktrace() or custom error handlers).User::macro('withRoles', fn() => ...))OrderService::macro('calculateTax', ...))Macroable::extend('App', fn($app) => $app->macro('...')))README.md for domain-specific methods?Xdebug or Laravel Debugbar in production-like loads.composer require wp-starter/macroable.AppServiceProvider to register global macros:
use WPStarter\Macroable\Macroable;
public function boot()
{
Macroable::extend('App\Models\User', function ($user) {
$user->macro('isAdmin', fn() => $user->role === 'admin');
});
}
Macroable::extend('App', fn($app) => $app->macro('featureFlag', fn($name) => config("flags.$name")));
// Usage: App::featureFlag('new_ui');
User).Order::macro('applyDiscount', ...)).Domain/Macros/README.md.AppServiceProvider for app-wide use.@cache or once() if needed:
$user->macro('expensiveCalc', fn() => Cache::remember('user_'.$user->id, 3600, fn() => ...));
hasMacro() checks):
if (!method_exists($user, 'isAdmin')) {
$user->macro('isAdmin', fn() => ...);
}
| Step | Action | Owner | Dependencies |
|---|---|---|---|
| 1. Install Package | composer require wp-starter/macroable |
DevOps/TPM | Composer access |
| 2. POC | Add macro to User model |
Backend Dev | Laravel setup |
| 3. Test | Unit tests + manual verification | QA/Backend Dev | PHPUnit/Pest |
| 4. Document | Update Domain/Macros/README.md |
TPM | None |
| 5. Globalize | Register in AppServiceProvider |
Backend Dev | POC success |
| 6. Deprecate | Replace legacy methods with macros (if applicable) | Backend Dev | Code review |
| 7. Benchmark | Compare performance vs. static methods | Performance | Load testing tools |
| 8. Train Team | Workshop on macro patterns and debugging | TPM/Tech Lead | None |
Order::macro('calculateTax', ...)).@method tags).dd($user->isAdmin) to inspect macro behavior.__call() in tests to mock macros:
$user->shouldReceive('isAdmin')->andReturn(true);
try-catch for graceful failures:
try {
$result = $user->isAdmin();
} catch (BadMethodCallException $e) {
Log::error("Macro failed: " . $e->getMessage());
return false;
}
config/macros.php) listing all macros and their purposes.microtime(true)).$user->macro('isAdmin', fn() => Cache::remember(...)).once() for expensive one-time calculations.__call() is stateless).Sync locks or database transactions.| Failure Scenario | Impact | Mitigation Strategy |
|---|---|---|
| Macro name collision | Silent override or BadMethodCallException |
Use hasMacro() checks; namespace methods. |
| Reflection errors (PHP 8+) | Error on undefined macros |
Validate macros exist before calling. |
| Performance degradation | Slow responses in loops | Benchmark; replace with static methods if needed. |
| Team misuses macros | Spaghetti logic | Enforce code reviews; limit macro scope. |
| Package abandonment | No updates | Fork or replace with Laravel’s built-in macros. |
How can I help you explore Laravel packages today?