PHPackages                             yceruto/decorator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. yceruto/decorator

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

yceruto/decorator
=================

PHP function decorators

v1.3.3(1y ago)31604MITPHPPHP &gt;=8.2

Since Sep 19Pushed 1y ago2 watchersCompare

[ Source](https://github.com/yceruto/decorator)[ Packagist](https://packagist.org/packages/yceruto/decorator)[ RSS](/packages/yceruto-decorator/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)Dependencies (6)Versions (8)Used By (4)

PHP Callable Decorator
======================

[](#php-callable-decorator)

[![GitHub Actions Workflow Status](https://camo.githubusercontent.com/25cad778e4d376f2b8b2910ea9dd4d97c2d3fcf6a194a277e3c5895a4deae980/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7963657275746f2f6465636f7261746f722f63692e796d6c)](https://camo.githubusercontent.com/25cad778e4d376f2b8b2910ea9dd4d97c2d3fcf6a194a277e3c5895a4deae980/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7963657275746f2f6465636f7261746f722f63692e796d6c)[![Version](https://camo.githubusercontent.com/99645db45e489a79145d59ede575a758865fbe888bd56de6c0245fd509753b43/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64796e616d69632f6a736f6e3f75726c3d68747470732533412532462532467265706f2e7061636b61676973742e6f726725324670322532467963657275746f2532466465636f7261746f722e6a736f6e2671756572793d2532342e7061636b616765732535422532327963657275746f2532466465636f7261746f72253232253544253542302535442e76657273696f6e266c6162656c3d76657273696f6e)](https://camo.githubusercontent.com/99645db45e489a79145d59ede575a758865fbe888bd56de6c0245fd509753b43/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64796e616d69632f6a736f6e3f75726c3d68747470732533412532462532467265706f2e7061636b61676973742e6f726725324670322532467963657275746f2532466465636f7261746f722e6a736f6e2671756572793d2532342e7061636b616765732535422532327963657275746f2532466465636f7261746f72253232253544253542302535442e76657273696f6e266c6162656c3d76657273696f6e)[![PHP](https://camo.githubusercontent.com/05e6b976b3f4b415af6da335201e0b92f070f1cb470183c4312a6876c5263fa3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64796e616d69632f6a736f6e3f75726c3d68747470732533412532462532466769746875622e636f6d2532467963657275746f2532466465636f7261746f722532467261772532466d61696e253246636f6d706f7365722e6a736f6e2671756572793d726571756972652e706870266c6162656c3d706870)](https://camo.githubusercontent.com/05e6b976b3f4b415af6da335201e0b92f070f1cb470183c4312a6876c5263fa3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64796e616d69632f6a736f6e3f75726c3d68747470732533412532462532466769746875622e636f6d2532467963657275746f2532466465636f7261746f722532467261772532466d61696e253246636f6d706f7365722e6a736f6e2671756572793d726571756972652e706870266c6162656c3d706870)[![GitHub License](https://camo.githubusercontent.com/34f262eba36de577587583c8384711af267ed0b893b3eb2051363d98ad93dd14/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f7963657275746f2f6465636f7261746f72)](https://camo.githubusercontent.com/34f262eba36de577587583c8384711af267ed0b893b3eb2051363d98ad93dd14/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f7963657275746f2f6465636f7261746f72)

Note

Inspired by [Python's decorator](https://peps.python.org/pep-0318/)

This library implements the [Decorator Pattern](https://en.wikipedia.org/wiki/Decorator_pattern) around any [PHP callable](https://www.php.net/manual/en/language.types.callable.php), 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
------------

[](#installation)

```
composer require yceruto/decorator
```

Usage
-----

[](#usage)

### Example 1 - Minimalistic

[](#example-1---minimalistic)

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

#[\Attribute(\Attribute::TARGET_METHOD)]
class Debug extends DecoratorAttribute 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

```

### Example 2 - Split decorator metadata from its implementation

[](#example-2---split-decorator-metadata-from-its-implementation)

You can separate the decorator attribute from its implementation whenever necessary:

```
use Yceruto\Decorator\Attribute\DecoratorAttribute;
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;
        };
    }
}
```

The `DecoratorAttribute` automatically links to its corresponding decorator class if the decorator is in the same directory, shares the same base name, and ends with the `*Decorator` suffix. If these conditions are not met, you must define the `decoratedBy()` method to establish the link manually.

### Example 3 - Decorating invokable objects

[](#example-3---decorating-invokable-objects)

In this example, the `Debug` attribute is used to decorate an invokable object. The decorator logic will be applied when the `__invoke()` method is called.

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

Important

The attribute will only be collected if there are no other decorator attributes defined on the `__invoke` method.

### Example 4 - Adding configuration to your decorator

[](#example-4---adding-configuration-to-your-decorator)

Add options through your attribute `__construct()` method, and pass them at the end of your `decorate()` method:

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

#[\Attribute(\Attribute::TARGET_METHOD)]
class Debug extends DecoratorAttribute implements DecoratorInterface
{
    public function __construct(
        private readonly string $prefix = '',
    ) {
    }

    public function decorate(\Closure $func, self $debug = new self()): \Closure
    {
        return function (mixed ...$args) use ($func, $debug): mixed
        {
            echo $debug->prefix."Do something before\n";

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

            echo $debug->prefix."Do something after\n";

            return $result;
        };
    }
}

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

Output:

```
Greeting: Do something before
Hello John!
Greeting: Do something after

```

Frameworks Integration
----------------------

[](#frameworks-integration)

- Symfony:

Decorators
----------

[](#decorators)

### Compound

[](#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
     */
    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
-------

[](#license)

This software is published under the [MIT License](LICENSE)

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance41

Moderate activity, may be stable

Popularity14

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~14 days

Recently: every ~1 days

Total

7

Last Release

518d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ebf906be9b4bb0c2060846ce9bbfe246df4e32bb5a8741ce1971ee923db2f8ae?d=identicon)[yceruto](/maintainers/yceruto)

---

Top Contributors

[![yceruto](https://avatars.githubusercontent.com/u/2028198?v=4)](https://github.com/yceruto "yceruto (24 commits)")

---

Tags

wrapperdecorator

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/yceruto-decorator/health.svg)

```
[![Health](https://phpackages.com/badges/yceruto-decorator/health.svg)](https://phpackages.com/packages/yceruto-decorator)
```

###  Alternatives

[symfony/dependency-injection

Allows you to standardize and centralize the way objects are constructed in your application

4.2k431.1M7.5k](/packages/symfony-dependency-injection)[simplesoftwareio/simple-qrcode

Simple QrCode is a QR code generator made for Laravel.

2.9k27.6M92](/packages/simplesoftwareio-simple-qrcode)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

728272.9k20](/packages/civicrm-civicrm-core)[artisaninweb/laravel-soap

A SoapClient wrapper integration for Laravel

6314.5M12](/packages/artisaninweb-laravel-soap)[mhor/php-mediainfo

PHP wrapper around the mediainfo command

120574.8k7](/packages/mhor-php-mediainfo)[samrap/acf-fluent

A fluent interface for the Advanced Custom Fields WordPress plugin

28656.0k4](/packages/samrap-acf-fluent)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
