PHPackages                             aimeos/macro - 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. aimeos/macro

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

aimeos/macro
============

Customize classes using closures

1.0.2(1y ago)2.3k131.7k—3%13MITPHPPHP ~7.1||~8.0CI passing

Since Dec 8Pushed 4mo ago2 watchersCompare

[ Source](https://github.com/aimeos/macro)[ Packagist](https://packagist.org/packages/aimeos/macro)[ RSS](/packages/aimeos-macro/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (2)Versions (5)Used By (3)

PHP Macro
---------

[](#php-macro)

The PHP Macro package offers closure (anonymous function) based setter dependency injection by providing a trait which can be included into any class.

```
composer req aimeos/macro
```

This package is for application, framework and library developers who want to allow customizing the behavior of their code by their users.

Why macros
----------

[](#why-macros)

In applications, frameworks or libraries which are build for customization it’s necessary to allow overwriting existing functionality to be able customize its behavior. This is where macros are very handy because they can add custom code using closures.

With the PHP Macro package, you can also allow users to overwrite methods in base classes without forcing your users to extend these classes. The PHP Macro package uses **NO reflection** or other hacks, just **pure PHP methods**.

There are some pros and cons when compared to class based depencency injection:

**Pro:**

- Less code to write and much easier to implement for simple stuff
- Custom closures can be inherited and overwritten like class methods

**Con:**

- Limited static code analysis possibilities
- Anonymous function can not be forced to implement an interface

Thus, it's not a replacement for class based depencency injection but a lightweight addition for small extension points where full-blown dependency injection using classes implementing interfaces are too much work.

Allow customization
-------------------

[](#allow-customization)

The result of existing methods can be modified if the original method checks for an existing macro and use that instead its own implementation:

```
// original code

class Order
{
    use Aimeos\Macro\Macroable;

    private $id = '123';

    public function getOrderNumber()
    {
        $fcn = static::macro( 'orderNumber' );
        return $fcn ? $fcn( $this->id ) : $this->id;
    }
};
```

Now, you can add your custom `orderNumber` macro that will be used instead:

```
// user code

Order::macro( 'orderNumber', function( string $id ) {
   return date( 'Y' ) . '-' . $id;
} );

(new Order)->getOrderNumber(); // now returns '2020-123'
```

Thus, you can generate own output or pass a different result to subseqent methods within the application.

Access class properties
-----------------------

[](#access-class-properties)

When macros are called in an object context, they can also access class properties:

```
// original code

class A
{
    use Aimeos\Macro\Macroable;
    private $name = 'A';
};
```

Here, the private property `$name` is available in the macro:

```
// user code

A::macro( 'concat', function( array $values ) {
   return $this->name . ':' . implode( '-', $values );
} );

(new A)->concat( ['1', '2', '3'] ); // returns 'A:1-2-3'
```

The macro can use the property as input for creating the returned value.

Use inherited macros
--------------------

[](#use-inherited-macros)

The PHP macro package also allows to inherit macros from parent classes. Then, they can access class properties of the child class just like regular class methods:

```
// original code

class A
{
    use Aimeos\Macro\Macroable;
    private $name = 'A';
};

class B extends A
{
    private $name = 'B';
};
```

Macros added to the parent class will be available in child classes too:

```
// user code

A::macro( 'concat', function( array $values ) {
   return $this->name . ':' . implode( '-', $values );
} );

(new B)->concat( ['1', '2', '3'] ); // returns 'B:1-2-3'
```

Class `B` extends from class `A` but provides a different `$name` property. The macro inherited from class `A` will now use the property of class `B`.

Overwrite inherited macros
--------------------------

[](#overwrite-inherited-macros)

It's also possible to overwrite macros inherited from parent classes as it's possible with regular class methods:

```
// original code

class A
{
    use Aimeos\Macro\Macroable;

    public function do() {
        return static::macro( 'concat' )( [1, 2, 3] );
    }
};

class B extends A {};

class C extends A {};
```

Now you can add macros to the parent class and one of the child classes:

```
// user code

A::macro( 'concat', function( array $values ) {
   return implode( ',', $values );
} );

C::macro( 'concat', function( array $values ) {
   return implode( '-', $values );
} );

(new B)->do(); // returns '1,2,3'

(new C)->do(); // returns '1-2-3'
```

This enables you to add special handling for single classes even if all other classes still use the macro added to class `A`.

Overwrite protected methods
---------------------------

[](#overwrite-protected-methods)

Base classes often offer a set of methods that are used by the child classes. In PHP, replacing the methods of a base class is impossible and thus, you have to overwrite each child class with your own implementation.

To avoid that, the original method can use the `call()` method instead of calling the method of the parent class directly:

```
// original code

class A
{
    use Aimeos\Macro\Macroable;

    protected function getName( $prefix )
    {
        return $prefix . 'A';
    }
};

class B extends A
{
    public function do()
    {
        return $this->call( 'getName', 'B-' );
    }
};
```

This will check if there's a macro `getName` available and will call that instead of the `getName()` method:

```
// user code

(new B)->do(); // returns 'B-A'

A::macro( 'getName', function( $prefix ) {
   return $this->getName( $prefix ) . '-123';
} );

(new B)->do(); // returns 'B-A-123'
```

The original `getName()` method can still be used in the macro.

Reset macros
------------

[](#reset-macros)

Sometimes, it may be necessary to remove macros from objects, especially when running automated tests. You can unset a macro by using:

```
class A
{
    use Aimeos\Macro\Macroable;
};

// add macro
A::macro( 'test', function() {
   return 'test';
} );

// remove macro
A::unmacro( 'test' );
```

###  Health Score

51

—

FairBetter than 96% of packages

Maintenance60

Regular maintenance activity

Popularity53

Moderate usage in the ecosystem

Community15

Small or concentrated contributor base

Maturity58

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 ~355 days

Total

4

Last Release

558d ago

### Community

Maintainers

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

---

Top Contributors

[![aimeos](https://avatars.githubusercontent.com/u/8647429?v=4)](https://github.com/aimeos "aimeos (31 commits)")

---

Tags

classclosurecustomcustomizedynamicextendinheritmacromacrosphp

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/aimeos-macro/health.svg)

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

###  Alternatives

[lochmueller/autoloader

Automatic components loading of ExtBase extensions to get more time for coffee in the company ;) This ext is not a PHP SPL autoloader or class loader - it is better! Loads CommandController, Xclass, Hooks, FlexForms, Slots, TypoScript, TypeConverter, BackendLayouts and take care of createing needed templates, TCA configuration or translations at the right location.

19364.9k5](/packages/lochmueller-autoloader)[justintadlock/hybrid-font

Helper functions for loading font stylesheets in WordPress themes.

146.4k](/packages/justintadlock-hybrid-font)[ircmaxell/php-types

A PHP CFG Type Inference / Reconstruction Engine

361.0k](/packages/ircmaxell-php-types)

PHPackages © 2026

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