PHPackages                             siriusphp/stratum - 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. siriusphp/stratum

AbandonedArchivedLibrary

siriusphp/stratum
=================

General purpose library that allows extending the functionality of your objects through a decorator-like mechanism

751[2 issues](https://github.com/siriusphp/stratum/issues)PHP

Since Feb 16Pushed 11y ago2 watchersCompare

[ Source](https://github.com/siriusphp/stratum)[ Packagist](https://packagist.org/packages/siriusphp/stratum)[ RSS](/packages/siriusphp-stratum/feed)WikiDiscussions master Synced today

READMEChangelogDependenciesVersions (2)Used By (0)

\#Sirius Stratum

[![Build Status](https://camo.githubusercontent.com/c3f87edf83f0ac04af6c60f5d89a227c4a48f45f0114a40b0703afac0e770b54/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f7369726975737068702f7374726174756d2f6261646765732f6275696c642e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/siriusphp/stratum/build-status/master)[![Code Coverage](https://camo.githubusercontent.com/dbad1dd14601fed0ba9420f4cd233a3492a02783708f49fc02315507990d94ae/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f7369726975737068702f7374726174756d2f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/siriusphp/stratum/?branch=master)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/2ceb16da06d27810980b7f5e7aedb4ef6a8e783fc45f1bc7418796fabfcca281/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f7369726975737068702f7374726174756d2f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/siriusphp/stratum/?branch=master)

`Sirius\Stratum` is a library that will allow you to create extensible systems without having to use:

1. **Deep inheritance**. Inherintance can take you not that far when it comes to create extensible classes.
2. **Traits**. Traits overcome the limitations of inherintance but they require to define the structure up-front (you cannot add traits at run-time)
3. **Event systems**. Event systems require you to write lots of code for everything that requires interaction with the event system.
4. **Command busses**. Command busses allow you to change the behaviour of the system by having different functions respond to a command but composing these function is very easy. Think of a `getLatestPosts` command that should retrieve the posts from database; you attach a callback to that command but later you want to implement a cache mechanism (ie: query the cache first and delegate to the previous callback if items are not in cache)
5. **AOP** (Aspect Oriented Programming). AOP is difficult because of the terminology and implementations are "heavy".  is ones of such implementations

Having said that, I must warn you that the `Sirius\Stratum` is not flawless and has some trade-offs (very small).

How does it work?
-----------------

[](#how-does-it-work)

The project started with the question: how can you make a method of a class change its behaviour at run-time while preserving the inheritance? The obvious answer is wrapping an object inside other similar to an onion. From this point of view `Sirius\Stratum` is similar to the decorator pattern. Imagine you have an ORM and you want to:

1. Log the calls (for benchmarking purposes)
2. Intercept exceptions to send notifications to the developer
3. Cache the results

```
$orm = new CacheBehaviour(new LogBehaviour( new ExceptionNotifier(new ORM($dbConn))));
$orm->getLatestArticles();
```

This is how one would implement this using the decorator pattern. There are some limitations/issues with this approach

1. If at the bottom of the callstack the `ORM` object calls another of its methods (eg: `getLatestArticles()` calls `$this->executeQuery()`) the call to that method will not go through the layers above
2. Your decorators will have to implement the same interface of the decorated class. Granted this can be automated (ie: have a mechanism to automatically create the decorator class on disk)

Now enter **Sirius\\Stratum**!

#### 1. Move your code into a "Base" class

[](#1-move-your-code-into-a-base-class)

```
class ORMBase {

	function __construct($dbConn) {
		// whatever...
	}

	function getLatestArticles() {
		// query the database, map the results, return a collection
	}
}

class ORM extends ORMBase {
	use \Sirius\Stratum\LayerableTrait;
}
```

**Note!** For PHP5.3 you'll need to copy&amp;paste the code from the `\Sirius\Stratum\LayerableTrait` trait yourself. Sorry!

#### 2. Decide which methods you want to be extendable/decoratable

[](#2-decide-which-methods-you-want-to-be-extendabledecoratable)

```
class ORM extends ORMBase {
	use \Sirius\Stratum\LayerableTrait;

	function getLatestArticles() {
		return $this->executeLayeredMethod(__FUNCTION__, func_get_args());
	}
}
```

#### 3. Instruct the Stratum Manager what layers to add to the target class

[](#3-instruct-the-stratum-manager-what-layers-to-add-to-the-target-class)

```
$manager = new Sirius\Stratum\Manager();
$manager->add('CacheBehaviour', 'ORM', -1000); // -1000 is the priority (not mandatory though)
$manager->add('LogBehaviour', 'ORM', 999);
$manager->add('ExceptionNotifier', 'ORM', 998);

// add decorators by TRAIT
$manager->add('LogBehaviour', 'uses:Vendor\Package\LoggableTrait');

// add decorators by INTERFACE
$manager->add('LogBehaviour', 'implements:Vendor\Package\LoggableInterface');

// add decorator by PARENT CLASS
$manager->add('LogBehaviour', 'extends:Vendor\Package\SomeBaseClass');

// attach the layers on the target method
$ormInstance->setTopLayer($manager->createLayerStack($ormInstance));
```

The layers classes must extend the `Sirius\Stratum\Layer` class.

### That's it!

[](#thats-it)

FAQ?
----

[](#faq)

#### 1. What are the trade-offs?

[](#1-what-are-the-trade-offs)

1. It is not a "pure" implementation of a pattern. [People complained](http://www.reddit.com/r/PHP/comments/2pke2j/aop_without_aop/) that it is either the Mediator pattern, the Chain of Responsibility pattern or a disquised Event pattern.
2. You have global state (ie: a singleton manager of the "strata" for each class). I consider the implementation to be similar to having traits (at the global level you define the traits) and I am not a purist.
3. Since the layers (or "decorators") are not required to implement the interface of the decorated object the library relies on `__call()` to pass the calls to the next layers, which come with a performance penalty. I will try to address this issue in the future though.

#### 2. Am I limited to classes for behaviour?

[](#2-am-i-limited-to-classes-for-behaviour)

No. You can add an object as a decorator (the object will be cloned whenever needed by that class though, so keep that in mind) or a callback/function that returns a decorator.

```
$manager->add($someAlreadyInstanciatedLayer, 'ORM');
$manager->add($someCallableThatReturnsALayer, 'ORM');
```

#### 1. What happens if the decorators have the same priority?

[](#1-what-happens-if-the-decorators-have-the-same-priority)

They will be called in the reverse order they where added (ie: the last will wrap around the first).

```
$manager->add('LayerA', 'LayerableClass', 100);
$manager->add('LayerB', 'LayerableClass', 100);

$decoratedClassObject->foo();
```

Assuming those are the only decorators `DecoratorB::foo()` will be called first which might call `LayerA::foo()` which might call `LayerableClass::foo()`

#### 4. Can I add a decorator multiple times?

[](#4-can-i-add-a-decorator-multiple-times)

Yes. The manager doesn't check if a decorator is attached to a class so be careful.

#### 5. Can I still use events?

[](#5-can-i-still-use-events)

Yes. You can have a decorator that will emit events. It might even make your life easier (use the same decorator on ALL the classes where you need that).

```
class EventsLayer extends Sirius\Stratum\Layer {

	function foo() {
		$this->emit('before_foo', func_get_args());
		return $this->callNext(__FUNCTION__, func_get_args());
	}

}
```

#### 6. Since I like decorators so much can I decorate a decorator?

[](#6-since-i-like-decorators-so-much-can-i-decorate-a-decorator)

Haven't tested it yet but I don't see why not.

###  Health Score

21

—

LowBetter than 21% of packages

Maintenance14

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% 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.

### Community

Maintainers

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

---

Top Contributors

[![adrianmiu](https://avatars.githubusercontent.com/u/1293017?v=4)](https://github.com/adrianmiu "adrianmiu (3 commits)")[![kandy](https://avatars.githubusercontent.com/u/100289?v=4)](https://github.com/kandy "kandy (1 commits)")

### Embed Badge

![Health badge](/badges/siriusphp-stratum/health.svg)

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

PHPackages © 2026

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