PHPackages                             chillerlan/php-settings-container - 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. chillerlan/php-settings-container

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

chillerlan/php-settings-container
=================================

A container class for immutable settings objects. Not a DI container.

4.0.0(1mo ago)3427.3M↑11%419MITPHPPHP ^8.4CI passing

Since Aug 28Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/chillerlan/php-settings-container)[ Packagist](https://packagist.org/packages/chillerlan/php-settings-container)[ Docs](https://github.com/chillerlan/php-settings-container)[ Fund](https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4)[ Fund](https://ko-fi.com/codemasher)[ RSS](/packages/chillerlan-php-settings-container/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (12)Versions (27)Used By (19)

chillerlan/php-settings-container
=================================

[](#chillerlanphp-settings-container)

A container class for settings objects - decouple configuration logic from your application! Not a DI container.

- [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerInterface.php) provides fancy [property hooks](https://wiki.php.net/rfc/property-hooks) for PHP &lt; 8.4.

[![PHP Version Support](https://camo.githubusercontent.com/4e9ab770db3742ab79691a86a8776b31eace986a3844517a43507f74562ab7c4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6368696c6c65726c616e2f7068702d73657474696e67732d636f6e7461696e65723f6c6f676f3d70687026636f6c6f723d383839324246)](https://www.php.net/supported-versions.php)[![version](https://camo.githubusercontent.com/b73ffa2cd99931a447bcf9bc6352fe354dd47560cb7dde82cccdfc30b5c82ff4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6368696c6c65726c616e2f7068702d73657474696e67732d636f6e7461696e65722e7376673f6c6f676f3d7061636b6167697374)](https://packagist.org/packages/chillerlan/php-settings-container)[![license](https://camo.githubusercontent.com/95d2e8266810f52a79c4ba6bc3bd60cf021a2cc34082502a45e9cd1c7cefca26/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6368696c6c65726c616e2f7068702d73657474696e67732d636f6e7461696e65722e737667)](https://github.com/chillerlan/php-settings-container/blob/main/LICENSE)[![Continuous Integration](https://camo.githubusercontent.com/63ec377f141811eb1196847c674989ceb9551ae758ca42b264ad2e289f3f0390/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6368696c6c65726c616e2f7068702d73657474696e67732d636f6e7461696e65722f63692e796d6c3f6272616e63683d6d61696e266c6f676f3d676974687562)](https://github.com/chillerlan/php-settings-container/actions/workflows/ci.yml?query=branch%3Amain)[![Coverage](https://camo.githubusercontent.com/7647b72c71fa7fa1fc0c739a924ab7c2d4e715e4ff19e3cd8310b9530ca1082e/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f6368696c6c65726c616e2f7068702d73657474696e67732d636f6e7461696e65722e7376673f6c6f676f3d636f6465636f76)](https://codecov.io/github/chillerlan/php-settings-container)[![Codacy](https://camo.githubusercontent.com/2837541dedf7dc1bbdfa6ad14565cf9a7a9dbd1bb26c518fc5ca2958015b9a73/68747470733a2f2f696d672e736869656c64732e696f2f636f646163792f67726164652f62643234363737393965323934336432383533636533656261643561663439302f6d61696e3f6c6f676f3d636f64616379)](https://app.codacy.com/gh/chillerlan/php-settings-container/dashboard?branch=main)[![Packagist downloads](https://camo.githubusercontent.com/1e6261597558862151b575492b5bc2e98141892aa2bdaae1cd1c3001fc3562c3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6368696c6c65726c616e2f7068702d73657474696e67732d636f6e7461696e65722e7376673f6c6f676f3d7061636b6167697374)](https://packagist.org/packages/chillerlan/php-settings-container/stats)

Documentation
-------------

[](#documentation)

### Installation

[](#installation)

**requires [composer](https://getcomposer.org)**

*composer.json* (note: replace `dev-main` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^3.0` - see [releases](https://github.com/chillerlan/php-settings-container/releases) for valid versions)

```
{
	"require": {
		"php": "^8.4",
		"chillerlan/php-settings-container": "dev-main"
	}
}
```

Profit!

Usage
-----

[](#usage)

The `SettingsContainerInterface` (wrapped in`SettingsContainerAbstract`) provides plug-in functionality for immutable object properties and adds some fancy, like loading/saving JSON, arrays etc. It takes an `iterable` as the only constructor argument and calls a method with the trait's name on invocation (`MyTrait::MyTrait()`) for each used trait.

A PHPStan ruleset to exclude errors generated by accessing magic properties on `SettingsContainerInterface` can be found in `rules-magic-access.neon`.

### Simple usage

[](#simple-usage)

```
class MyContainer extends SettingsContainerAbstract{
	protected string $foo;
	protected string $bar;
}
```

```
// use it just like a \stdClass (except the properties are fixed)
$container = new MyContainer;
$container->foo = 'what';
$container->bar = 'foo';

// which is equivalent to
$container = new MyContainer(['bar' => 'foo', 'foo' => 'what']);
// ...or try
$container->fromJSON('{"foo": "what", "bar": "foo"}');

// fetch all properties as array
$container->toArray(); // -> ['foo' => 'what', 'bar' => 'foo']
// or JSON
$container->toJSON(); // -> {"foo": "what", "bar": "foo"}
// JSON via JsonSerializable
$json = json_encode($container); // -> {"foo": "what", "bar": "foo"}
```

By default, non-existing properties will be ignored and return `null`:

```
$container->nope = 'what';

var_dump($container->nope); // -> null
```

You can change this behaviour by adding the attribute `ThrowOnInvalidProperty` to your container class:

```
#[ThrowOnInvalidProperty(true)]
class MyContainer extends SettingsContainerAbstract{
	// ...
}

$container->nope = 'what'; // -> throws: attempt to write invalid property: "$nope"
```

### Advanced usage

[](#advanced-usage)

Suppose the following trait from library 1:

```
trait SomeOptions{
	protected string $foo;
	protected string $what;

	// this method will be called in SettingsContainerAbstract::construct()
	// after the properties have been set
	protected function SomeOptions():void{
		// just some constructor stuff...
		$this->foo = strtoupper($this->foo);
	}

	/*
	 * special prefixed magic setters & getters ("set_"/"get_" + property name)
	 */

	// this method will be called from __set() when property $what is set
	protected function set_what(string $value):void{
		$this->what = md5($value);
	}

	// this method is called on __get() for the property $what
	protected function get_what():string{
		return 'hash: '.$this->what;
	}
}
```

And another trait from library 2:

```
trait MoreOptions{
	protected string $bar = 'whatever'; // provide default values
}
```

We can now plug the several library options together to a single class/object:

```
$commonOptions = [
	// SomeOptions
	'foo' => 'whatever',
	// MoreOptions
	'bar' => 'nothing',
];

$container = new class ($commonOptions) extends SettingsContainerAbstract{
	use SomeOptions, MoreOptions;
};

var_dump($container->foo); // -> WHATEVER (constructor ran strtoupper on the value)
var_dump($container->bar); // -> nothing

$container->what = 'some value';
var_dump($container->what); // -> hash: 5946210c9e93ae37891dfe96c3e39614 (custom getter added "hash: ")
```

### A note on property hooks (PHP 8.4+)

[](#a-note-on-property-hooks-php-84)

Property hooks are called whenever a property is accessed (except from within the hook itself of course), which means that the custom get/set methods this library allows would conflict when a custom method is defined for a property that also has a hook defined. To prevent double method calls, the internal methods `hasSetHook()` and `hasGetHook()` have been introduced, and are called whenever the magic get/set methods are called: when both, a custom method and a property hook exist, only the property hook will be called.
Public properties will never call the magic get/set, however, their hooks *will* be called. (un)serializing a `SettingsContainerInterface` instance will bypass magic get/set and existing property hooks, while JSON de/encode as will call magic get/set or existing hooks explicitly via the `toArray()` and `fromIterable()` methods.

```
class PropertyHooksContainer extends SettingsContainerAbstract{

	protected string $someValue{
		set => doStuff($value);
	}

	// this method will be ignored in magic calls as a "set" hook on the property exists
	protected function set_someValue(string $value):void{
		$this->someValue = doOtherStuff($value);
	}

	// this custom method will be called as the property has no "get" hook
	protected function get_someValue():string{
		return doWhatever($this->someValue);
	}

	// this property will never trigger the magic get/set and associated methods
	public string $otherValue{
		set => doStuff($value);
		get => $this->otherValue;
	}

}
```

### API

[](#api)

#### [`SettingsContainerAbstract`](https://github.com/chillerlan/php-settings-container/blob/main/src/SettingsContainerAbstract.php)

[](#settingscontainerabstract)

methodreturninfo`__construct(iterable $properties = null)`-calls `construct()` internally after the properties have been set`__get(string $property)`mixedcalls `$this->{'get_'.$property}()` if such a method exists`__set(string $property, $value)`voidcalls `$this->{'set_'.$property}($value)` if such a method exists`__isset(string $property)`bool`__unset(string $property)`void`__toString()`stringa JSON string`toArray()`array`fromIterable(iterable $properties)``SettingsContainerInterface``toJSON(int $jsonOptions = null)`stringaccepts [JSON options constants](http://php.net/manual/json.constants.php)`fromJSON(string $json)``SettingsContainerInterface``jsonSerialize()`mixedimplements the [`JsonSerializable`](https://www.php.net/manual/en/jsonserializable.jsonserialize.php) interface`serialize()`stringimplements the [`Serializable`](https://www.php.net/manual/en/serializable.serialize.php) interface`unserialize(string $data)`voidimplements the [`Serializable`](https://www.php.net/manual/en/serializable.unserialize.php) interface`__serialize()`arrayimplements the [`Serializable`](https://www.php.net/manual/en/language.oop5.magic.php#object.serialize) interface`__unserialize(array $data)`voidimplements the [`Serializable`](https://www.php.net/manual/en/language.oop5.magic.php#object.unserialize) interface#### Internal (protected) methods

[](#internal-protected-methods)

methodreturninfo`construct()`voidcalls a method with trait name as replacement constructor for each used trait`isPrivate(string $property)`boolprivate properties are excluded from magic calls`hasSetHook(string $property)`bool`hasGetHook(string $property)`boolDisclaimer
----------

[](#disclaimer)

This might be either an absolutely brilliant or completely stupid idea - you decide (in hindsight it was a great idea I guess - property hooks made their way into PHP 8.4).
Also, this is not a dependency injection container. Stop using DI containers FFS.

###  Health Score

70

—

ExcellentBetter than 100% of packages

Maintenance88

Actively maintained with recent releases

Popularity60

Solid adoption and visibility

Community21

Small or concentrated contributor base

Maturity90

Battle-tested with a long release history

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

Recently: every ~187 days

Total

24

Last Release

59d ago

Major Versions

2.1.4 → 3.0.02022-11-05

v1.2.x-dev → 2.1.52024-01-05

2.1.5 → 3.1.12024-01-05

2.1.6 → 3.3.02026-03-20

3.3.0 → 4.0.02026-03-20

PHP version history (6 changes)1.0.0PHP ^7.2

2.0.0PHP ^7.4

2.1.0PHP ^7.4 || ^8.0

1.2.2PHP ^7.2 || ^8.0

3.0.0PHP ^8.1

4.0.0PHP ^8.4

### Community

Maintainers

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

---

Top Contributors

[![codemasher](https://avatars.githubusercontent.com/u/592497?v=4)](https://github.com/codemasher "codemasher (150 commits)")

---

Tags

configurationconfiguration-managementphpphp7php8settingssettings-managementsettings-storagecontainerhelperconfigurationSettingsproperty hook

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/chillerlan-php-settings-container/health.svg)

```
[![Health](https://phpackages.com/badges/chillerlan-php-settings-container/health.svg)](https://phpackages.com/packages/chillerlan-php-settings-container)
```

###  Alternatives

[dmishh/settings-bundle

Database centric Symfony configuration management. Global and per-user settings supported.

115254.9k1](/packages/dmishh-settings-bundle)[michaels/data-manager

Simple data manager for nested data, dot notation array access, extendability, and container interoperability.

121.9k2](/packages/michaels-data-manager)

PHPackages © 2026

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