PHPackages                             dmitrijs-brujevs/data-object - 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. dmitrijs-brujevs/data-object

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

dmitrijs-brujevs/data-object
============================

Path-based in-memory data container with nested array access via slash-separated node paths.

2.1.2(3mo ago)09MITPHPPHP ^8.2CI passing

Since Mar 26Pushed 3mo agoCompare

[ Source](https://github.com/dmitrijs-brujevs/data-object)[ Packagist](https://packagist.org/packages/dmitrijs-brujevs/data-object)[ RSS](/packages/dmitrijs-brujevs-data-object/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (2)Dependencies (3)Versions (10)Used By (0)

DataObject
==========

[](#dataobject)

[![CI](https://github.com/dmitrijs-brujevs/data-object/actions/workflows/ci.yml/badge.svg)](https://github.com/dmitrijs-brujevs/data-object/actions/workflows/ci.yml)[![Latest Version](https://camo.githubusercontent.com/5bd76ba6c54289d9d9f8adeae29025c7efbc184cc833e3694f83748f1ec009b8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f646d697472696a732d6272756a6576732f646174612d6f626a6563742e737667)](https://packagist.org/packages/dmitrijs-brujevs/data-object)[![PHP Version](https://camo.githubusercontent.com/c9f64f714c636ba27a3bba6dfd52f98426832db1262747efa54b212d16943651/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e322d626c7565)](https://www.php.net/)[![License: MIT](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)

A lightweight, path-based in-memory data container for PHP 8.2+.

Stores data in a nested array and provides access via slash-separated node paths. No dependencies. No magic beyond what is documented.

---

Why this library?
-----------------

[](#why-this-library)

- You receive config, API responses, or form data as nested arrays and want clean, readable access without `$data['user']['address']['city'] ?? null` chains
- You want dot/slash-path notation with `isset`-safe existence checks
- You need a minimal, subclassable value object with no framework coupling

---

Requirements
------------

[](#requirements)

- PHP 8.2+
- `ext-json`

Installation
------------

[](#installation)

```
composer require dmitrijs-brujevs/data-object
```

---

Quick Start
-----------

[](#quick-start)

```
use DmitrijsBrujevs\DataObject\DataObject;

$obj = DataObject::fromArray([
    'user' => [
        'name'    => 'John',
        'role'    => 'admin',
        'address' => [
            'city'    => 'Riga',
            'country' => 'Latvia',
        ],
    ],
]);

$obj->get('user/name');              // "John"
$obj->get('user/address/city');      // "Riga"
$obj->has('user/role');              // true
$obj->is('user/role', 'admin');      // true
$obj->set('user/age', 30);
$obj->delete('user/role');

$obj->getOrDefault('user/email', 'n/a'); // "n/a" — key is absent
```

---

Creating an Instance
--------------------

[](#creating-an-instance)

Use the explicit factory methods when the input format is known:

```
// from array
$obj = DataObject::fromArray(['key' => 'value']);

// from JSON string
$obj = DataObject::fromJson('{"key":"value"}');

// from PHP serialized string (objects disallowed — see Security section)
$obj = DataObject::fromSerialized(serialize(['key' => 'value']));
```

The constructor also accepts all three formats via auto-detection:

```
$obj = new DataObject(['key' => 'value']);
$obj = new DataObject('{"key":"value"}');
$obj = new DataObject(serialize(['key' => 'value']));
```

An `InvalidArgumentException` is thrown if the string is neither valid JSON nor a serialized array.

---

Path Notation
-------------

[](#path-notation)

Each segment of a path corresponds to a key in the nested structure. The default delimiter is `/`, customisable per instance.

```
"user/address/city"  →  $data['user']['address']['city']
"config/db/port"     →  $data['config']['db']['port']

```

---

API Reference
-------------

[](#api-reference)

### `get(string $node = ''): mixed`

[](#getstring-node---mixed)

Returns the value at the given path.

- Nested array → returned as a new `DataObject` instance (same concrete class)
- Missing path → returns `null`
- No arguments → returns `$this` (root)

```
$obj->get('user/name');    // "John"
$obj->get('user');         // DataObject { name: "John", ... }
$obj->get('user/missing'); // null
$obj->get();               // $this
```

> **null vs missing:** `get()` returns `null` for both a missing path and an explicit `null` value. Use `has()` to distinguish them, or use `getOrDefault()`.

---

### `getOrDefault(string $node, mixed $default = null): mixed`

[](#getordefaultstring-node-mixed-default--null-mixed)

Returns the value at the given path, or `$default` if the node does not exist.

Unlike `get()`, this correctly distinguishes between a missing node and an explicit `null` value:

```
$obj->set('role', null);

$obj->getOrDefault('role', 'guest');    // null    — key exists, value is null
$obj->getOrDefault('missing', 'guest'); // "guest" — key does not exist
```

---

### `has(string $node): bool`

[](#hasstring-node-bool)

Returns `true` if the node exists, regardless of its value. Uses `array_key_exists` semantics.

```
$obj->set('role', null);
$obj->has('role');    // true  — key exists, value is null
$obj->has('email');   // false — key is absent
$obj->has('');        // true  — root always exists
```

---

### `is(string $node, mixed $value): bool`

[](#isstring-node-mixed-value-bool)

Strict equality check (`===`). Returns `false` if the node does not exist.

```
$obj->set('score', 10);
$obj->set('role', null);

$obj->is('score', 10);      // true
$obj->is('score', '10');    // false — int !== string
$obj->is('role', null);     // true  — key exists, value is null
$obj->is('missing', null);  // false — key does not exist
```

> **Note:** `is('missing', null)` returns `false` (changed in 2.1.0 — previously returned `true`). Use `has()` or `getOrDefault()` if the old behaviour was relied upon.

---

### `set(string|int $node, mixed $value): static`

[](#setstringint-node-mixed-value-static)

Sets a value at the given path. Intermediate nodes are created automatically. If an intermediate node holds a non-array value, it is replaced with an array. Returns `$this` for fluent chaining.

```
$obj->set('user/name', 'Jane');
$obj->set('user/address/zip', '1010');
$obj->set('user/role', null);

$obj->set('a', 1)->set('b', 2)->set('c', 3);
```

---

### `add(array $array, string $node = ''): static`

[](#addarray-array-string-node---static)

Recursively merges a nested array into the object. Existing values at the same paths are overwritten. Empty arrays are stored as-is — `get()` on that path returns an empty `DataObject`.

```
$obj->add(['user' => ['name' => 'John', 'age' => 30]]);
$obj->get('user/name'); // "John"

// with a path prefix
$obj->add(['host' => 'localhost', 'port' => 3306], 'config/db');
$obj->get('config/db/host'); // "localhost"

// empty array is stored, not ignored
$obj->add(['tags' => []]);
$obj->has('tags');  // true
$obj->get('tags');  // DataObject (empty)
```

---

### `delete(string $node): static`

[](#deletestring-node-static)

Removes the value at the given path. Only the final segment is removed; parent nodes and siblings remain intact. No-op for non-existent paths.

```
$obj->delete('user/role');
$obj->has('user/role');  // false
$obj->get('user/name');  // "John" — siblings intact

$obj->delete('user/age')->delete('user/email'); // fluent
```

---

### `toArray(): array`

[](#toarray-array)

Returns the internal storage as a plain nested PHP array.

```
$obj->toArray();
// ['user' => ['name' => 'John', 'age' => 30]]
```

---

### `toJson(int $flags, int $depth): string`

[](#tojsonint-flags-int-depth-string)

Returns the data encoded as a JSON string. Default flags: `JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES`.

```
$obj->toJson();
// {"user":{"name":"Иван","url":"https://example.com"}}

$obj->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
```

---

### `serialize(): string`

[](#serialize-string)

Returns the data as a PHP serialized string.

```
$serialized = $obj->serialize();
$restored   = DataObject::fromSerialized($serialized);
```

---

Magic camelCase Methods
-----------------------

[](#magic-camelcase-methods)

Any method prefixed with `get`, `set`, `has`, `is`, or `delete` is resolved by `__call()` at runtime. The name is split on uppercase letters and joined with the delimiter to form a path.

```
$obj->getUserName()           // → get('user/name')
$obj->setUserName('Jane')     // → set('user/name', 'Jane')
$obj->hasUserRole()           // → has('user/role')
$obj->isUserRole('admin')     // → is('user/role', 'admin')
$obj->deleteUserRole()        // → delete('user/role')
$obj->getUserAddressCity()    // → get('user/address/city')
```

Unknown prefixes throw `BadMethodCallException` (changed in 2.1.0 — previously returned `null`).

**Limitations:**

- Consecutive uppercase letters are split per character: `getURLPath()` → `get('u/r/l/path')`. Use explicit path strings for such keys.
- Multi-word method names (`getOrDefault`) cannot be dispatched via magic — the parser only recognises single-word prefixes.

---

Iteration
---------

[](#iteration)

`DataObject` implements `Iterator`. Nested arrays are automatically wrapped in `DataObject` instances at each level.

```
foreach ($obj as $key => $value) {
    // $value is DataObject if the element is a nested array
}

// nested foreach works across any depth
foreach ($obj as $continent => $countries) {
    foreach ($countries as $country => $info) {
        echo $info->get('capital');
    }
}
```

---

Custom Delimiter
----------------

[](#custom-delimiter)

```
$obj = DataObject::fromArray(['user' => ['name' => 'John']], delimiter: '.');

$obj->get('user.name'); // "John"
$obj->set('user.age', 30);
```

---

Subclassing
-----------

[](#subclassing)

`DataObject` is designed to be subclassed. All factory methods and internal wrapping use `new static()`, so nested arrays and iterator values are wrapped in the concrete subclass.

```
class UserObject extends DataObject {}

$user = UserObject::fromArray(['name' => 'John', 'roles' => ['admin', 'editor']]);
$user->get('roles'); // UserObject instance, not DataObject
```

Public method overrides in subclasses take full precedence — PHP routes them directly without going through `__call()`.

---

Security — Serialized Input
---------------------------

[](#security--serialized-input)

`fromSerialized()` and the constructor's auto-detection both use `unserialize($data, ['allowed_classes' => false])`.

This means:

- **No PHP objects are instantiated** during deserialization — gadget-chain attacks are blocked
- Only arrays are accepted; anything else throws `InvalidArgumentException`
- PHP warnings from malformed strings are caught via a temporary error handler, not `@`

**Only pass serialized data from sources you control.** Even with `allowed_classes = false`, deserializing untrusted user input is not recommended practice.

---

Running Locally
---------------

[](#running-locally)

```
composer install

composer test      # PHPUnit
composer stan      # PHPStan level 8
composer cs        # PHP-CS-Fixer (dry-run)
composer cs:fix    # PHP-CS-Fixer (apply)
composer check     # stan + cs + test
```

---

License
-------

[](#license)

MIT

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance80

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity71

Established project with proven stability

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

Recently: every ~457 days

Total

9

Last Release

103d ago

Major Versions

1.0.6 → 2.0.02026-04-11

PHP version history (3 changes)1.0.0PHP ^7.4

2.0.0PHP ^8.0

2.1.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/36db7daa30d5e194dbc01e003fa45f4c0404c7045d1602b76cd11c0ae58265dd?d=identicon)[dmitrijs.brujevs](/maintainers/dmitrijs.brujevs)

---

Top Contributors

[![dmitrijs-brujevs](https://avatars.githubusercontent.com/u/31079183?v=4)](https://github.com/dmitrijs-brujevs "dmitrijs-brujevs (16 commits)")

---

Tags

containerhelperarraynesteddatapathdot notation

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/dmitrijs-brujevs-data-object/health.svg)

```
[![Health](https://phpackages.com/badges/dmitrijs-brujevs-data-object/health.svg)](https://phpackages.com/packages/dmitrijs-brujevs-data-object)
```

###  Alternatives

[league/config

Define configuration arrays with strict schemas and access values with dot notation

567335.0M36](/packages/league-config)[grasmash/expander

Expands internal property references in PHP arrays.

13864.3M10](/packages/grasmash-expander)[michaels/data-manager

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

122.0k2](/packages/michaels-data-manager)[chillerlan/php-settings-container

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

3535.1M23](/packages/chillerlan-php-settings-container)[jbzoo/data

An extended version of the ArrayObject object for working with system settings or just for working with data arrays

851.6M23](/packages/jbzoo-data)[bocharsky-bw/arrayzy

A native PHP arrays easy manipulation library in OOP way.

38427.7k](/packages/bocharsky-bw-arrayzy)

PHPackages © 2026

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