Installation:
composer require hyperf/tappable
Ensure hyperf/framework is installed (this package extends Hyperf’s core).
First Use Case: Extend a Hyperf class (e.g., a service or command) with tappable macros. Example:
use Hyperf\Tappable\Macroable;
class MyService extends AbstractService implements Macroable
{
// Inherits macroable traits
}
MyService::macro('log', function ($message) {
\Hyperf\Logger\LoggerFactory::get('default')->info($message);
});
// Usage:
$service = new MyService();
$service->log('Hello, tappable!');
Key Files:
Macroable.php for trait methods.MacroableServiceProvider.php (if included) for global macros.Macroable Services:
Attach macros to Hyperf services (e.g., Request, Response, Container).
\Hyperf\HttpServer\Request::macro('isAdmin', function () {
return $this->input('role') === 'admin';
});
Command Extensions: Extend Hyperf commands with reusable logic:
\Hyperf\Command\Command::macro('askForConfirmation', function ($question) {
if (!\Hyperf\Support\env('APP_ENV') === 'production') {
return $this->ask($question, 'no') === 'yes';
}
return true;
});
Container Macros: Dynamically bind services or modify container behavior:
\Hyperf\Container\Container::macro('singletonIf', function ($abstract, $concrete, $condition) {
if ($condition) {
$this->singleton($abstract, $concrete);
}
});
Middleware Macros: Add reusable middleware logic:
\Hyperf\HttpServer\Middleware\Middleware::macro('validateJson', function () {
return function ($request, $next) {
if (!$request->isJson()) {
return \Hyperf\HttpServer\Response::json(['error' => 'Invalid JSON']);
}
return $next($request);
};
});
MyService::flushMacros();
config/macros.php) for organization.Macro Overwriting: Macros with the same name will overwrite each other. Use unique names or namespaces:
MyService::macro('App\Macros\log', function () { ... });
Static Context: Macros are static; avoid relying on instance state unless explicitly passed:
// Bad: Assumes $this refers to the macroable instance.
MyService::macro('getUser', function () {
return $this->user; // May fail if called statically.
});
// Good: Explicitly pass context.
MyService::macro('getUser', function ($service) {
return $service->user;
});
Hyperf-Specific Quirks:
on() or after() hooks. Use them for direct method extensions only.Performance: Macros add minimal overhead, but avoid heavy computations in macro definitions (e.g., database queries). Cache results if needed.
if (MyService::hasMacro('log')) {
// Macro exists.
}
print_r(MyService::getMacros());
\Hyperf\Logger\LoggerFactory to debug macro execution flow.Custom Macroable Traits:
Extend the Macroable trait for domain-specific macros:
trait MyMacroable {
public static function macro($name, $macro) {
static::macro($name, $macro);
}
}
Global Macros: Register macros globally in a service provider:
public function register()
{
\Hyperf\HttpServer\Request::macro('isApi', function () {
return $this->header('Accept') === 'application/json';
});
}
Macro Validation: Add validation to macros to ensure arguments are correct:
MyService::macro('safeDivide', function ($dividend, $divisor) {
if ($divisor === 0) {
throw new \InvalidArgumentException('Divisor cannot be zero.');
}
return $dividend / $divisor;
});
Macro Namespacing: Use namespaces to avoid collisions in large applications:
MyService::macro('Auth\validateToken', function ($token) { ... });
How can I help you explore Laravel packages today?