Skip to content

yceruto/decorator

Repository files navigation

PHP Callable Decorator

GitHub Actions Workflow Status Version PHP GitHub License

Note

Inspired by Python's decorator

This library implements the Decorator Pattern around any PHP callable, allowing you to:

  • Execute logic before or after a callable is executed
  • Skip the execution of a callable by returning earlier
  • Modify the result of a callable

Installation

composer require yceruto/decorator

Usage

use Yceruto\Decorator\Attribute\DecoratorAttribute;
use Yceruto\Decorator\CallableDecorator;
use Yceruto\Decorator\DecoratorInterface;

#[\Attribute(\Attribute::TARGET_METHOD)]
class Debug extends DecoratorAttribute
{
}

class DebugDecorator implements DecoratorInterface
{
    public function decorate(\Closure $func): \Closure
    {
        return function (mixed ...$args) use ($func): mixed
        {
            echo "Do something before\n";

            $result = $func(...$args);

            echo "Do something after\n";

            return $result;
        };
    }
}

class Greeting
{
    #[Debug]
    public function sayHello(string $name): void
    {
        echo "Hello $name!\n";
    }
}

$greeting = new Greeting();
$decorator = new CallableDecorator();
$decorator->call($greeting->sayHello(...), 'John');

Output:

Do something before
Hello John!
Do something after

Decorators

Compound

To create a reusable set of decorators, extend the Compound class:

use Yceruto\Decorator\Attribute\Compound;

#[\Attribute(\Attribute::TARGET_METHOD)]
class Greetings extends Compound
{
    /**
     * @return array<DecoratorAttribute>
     */
    public function getDecorators(array $options): array
    {
        return [
            new Hello(),
            new Welcome(),
            // ...
        ];
    }
}

class Greeting
{
    #[Greetings]
    public function __invoke(): void
    {
        // ...
    }
}

When the Greeting::__invoke() method is decorated, the Hello and Welcome decorator attributes will be applied in the specified order. This is equivalent to directly defining #[Hello] and #[Welcome] on this method.

License

This software is published under the MIT License