PHPackages                             nandan108/prop-access - 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. nandan108/prop-access

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

nandan108/prop-access
=====================

Accessor layer for PHP objects using reflection, extensible via custom resolvers

v0.7.0(2mo ago)0265↓33.3%2MITPHPPHP ^8.1CI passing

Since Jun 11Pushed 2mo agoCompare

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

READMEChangelog (5)Dependencies (4)Versions (9)Used By (2)

📦 prop-access
-------------

[](#-prop-access)

[![CI](https://github.com/nandan108/prop-access/actions/workflows/ci.yml/badge.svg)](https://github.com/nandan108/prop-access/actions/workflows/ci.yml/badge.svg)[![Coverage](https://camo.githubusercontent.com/63f39c020d23e0737bb3d60e6b9573dd9f21238359750760d714f7a04b460e61/68747470733a2f2f636f6465636f762e696f2f67682f6e616e64616e3130382f70726f702d6163636573732f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://camo.githubusercontent.com/63f39c020d23e0737bb3d60e6b9573dd9f21238359750760d714f7a04b460e61/68747470733a2f2f636f6465636f762e696f2f67682f6e616e64616e3130382f70726f702d6163636573732f6272616e63682f6d61696e2f67726170682f62616467652e737667)[![Style](https://camo.githubusercontent.com/77a781eb39a9e5a05b2ca0fb24ed710d9ba4e063d4077b5a622535447c5d4790/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c652d7068702d2d63732d2d66697865722d627269676874677265656e)](https://camo.githubusercontent.com/77a781eb39a9e5a05b2ca0fb24ed710d9ba4e063d4077b5a622535447c5d4790/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c652d7068702d2d63732d2d66697865722d627269676874677265656e)[![Packagist](https://camo.githubusercontent.com/36112030bfe1d89b0590f2a74a640969fecfac05903c066350883c68e70ba86c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e616e64616e3130382f70726f702d616363657373)](https://camo.githubusercontent.com/36112030bfe1d89b0590f2a74a640969fecfac05903c066350883c68e70ba86c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e616e64616e3130382f70726f702d616363657373)

**A minimal and extensible property accessor library for PHP objects.**

Provides getter and setter resolution via reflection, supporting both public properties and `get*/set*` methods.

Designed to be:

- ✅ Framework-agnostic
- 🔌 Easily extensible to support more object types

---

### 🛠 Installation

[](#-installation)

```
composer require nandan108/prop-access
```

---

### 🔧 Features

[](#-features-)

- 🧠 Default resolvers for public properties and `getProp()`/`setProp()` methods
- 🧩 Pluggable resolver priority (later-registered resolvers are called first)
- 🧼 `CaseConverter` utility for camelCase, snake\_case, kebab-case, etc.
- 🧰 Convenience methods: `getValueMap()`, `resolveValues()`, `canGetGetterMap()`...

---

### 🚀 Usage

[](#-usage)

Accessor maps are **cached by class name**, so the returned closures are **stateless** and require the target object to be passed as an argument:

```
use Nandan108\PropAccess\PropAccess;

$getterMap = PropAccess::getGetterMap($myObj);
$value = $getterMap['propertyName']($myObj);

$setterMap = PropAccess::getSetterMap($myObj);
$setterMap['propertyName']($myObj, $newValue);
```

To resolve only specific properties:

```
$getters = PropAccess::getGetterMap($myObj, ['foo_bar']);
```

#### 🧰 Convenience Utilities

[](#-convenience-utilities)

**Quickly resolve values from a target object:**

```
use Nandan108\PropAccess\PropAccess;

$values = PropAccess::getValueMap($myDto);
// → ['prop1' => 'value1', 'prop2' => 42, ...]
```

You can also resolve values from a previously obtained getter map:

```
$getters = PropAccess::getGetterMap($entity, ['foo', 'bar']);
$values = PropAccess::resolveValues($getters, $entity);
```

---

**Check if accessors are supported for a given target:**

```
if (PropAccess::canGetGetterMap($target)) {
    // Safe to call getGetterMap()
}
```

These methods are especially useful when working with dynamic sources, fallbacks, or introspection-based tools.

---

#### 🧐 Resolution Behavior

[](#-resolution-behavior)

You can call `getGetterMap()` / `getSetterMap()` in two ways:

1. **Without property list**: Returns a full canonical map using camelCase keys. If both a public property (e.g. `my_prop`) and a corresponding getter (`getMyProp()`) exist, **only the getter will be included** to avoid duplication and ensure value transformation logic is preserved.

    ```
    $map = PropAccess::getGetterMap($entity);
    $map['myProp']($entity); // uses getMyProp(), not $entity->my_prop
    ```
2. **With a property list**: Allows access to both public properties and getter/setter methods via multiple aliases:

    - `foo_bar` → accesses the public property (if available)
    - `fooBar` → accesses the getter/setter method (if available)

    ```
    [$directSetter, $indirectSetter] = PropAccess::getSetterMap($myObj, ['foo_bar', 'fooBar']);

    $directSetter($myObj, 'A');   // -> $myObj->foo_bar = 'A';
    $indirectSetter($myObj, 'B'); // -> $myObj->setFooBar('B');
    ```

---

### 🔌 Custom Accessor Resolvers

[](#-custom-accessor-resolvers)

Resolvers can be registered to override or extend behavior:

```
PropAccess::bootDefaultResolvers(); // Registers built-in property/method resolvers

// Deprecated: use registerResolvers([...]) instead.
PropAccess::registerGetterResolver(new MyCustomGetterResolver());
PropAccess::registerSetterResolver(new MyCustomSetterResolver());

// Register many at once:
PropAccess::registerResolvers([
    new MyCustomGetterResolver(),
    new MyCustomSetterResolver(),
]);

// Remove resolvers later (by class name or instance), as an array:
PropAccess::unregisterResolvers([
    MyCustomGetterResolver::class,
    MyCustomSetterResolver::class,
]);
```

Later-registered resolvers are tried first. If `->supports($object)` returns false, fallback continues down the chain. Registering the same resolver class multiple times is ignored. `registerGetterResolver()` and `registerSetterResolver()` remain available for backward compatibility, but are deprecated.

---

### 🧬 CaseConverter Utility

[](#-caseconverter-utility-)

```
CaseConverter::toCamel('user_name');     // "userName"
CaseConverter::toPascal('user_name');    // "UserName"
CaseConverter::toSnake('UserName');      // "user_name"
CaseConverter::toKebab('UserName');      // "user-name"
CaseConverter::toUpperSnake('UserName'); // "USER_NAME"
```

You can also use the generic method:

```
CaseConverter::to('camel', 'foo_bar'); // Equivalent to toCamel()
```

---

### 🔍 AccessorProxy Helper

[](#-accessorproxy-helper)

Need array-style access to object properties? `AccessorProxy` wraps an object and exposes property access via `ArrayAccess`, `Traversable`, and `Countable`.

```
use Nandan108\PropAccess\AccessorProxy;

$proxy = AccessorProxy::getFor($user); // read-only by default

echo $proxy['firstName'];      // -> $user->getFirstName()
$proxy['lastName'] = 'Smith';  // throws PropAccessConfigException (read-only)

$rwProxy = AccessorProxy::GetFor($user, readOnly: false);
$rwProxy['lastName'] = 'Smith'; // works if setLastName() or $lastName is available
```

Includes convenience methods:

```
$proxy->toArray(); // ['firstName' => 'John', ...]
$proxy->readableKeys();  // ['firstName', 'lastName', ...]
$proxy->writeableKeys();
```

Use `AccessorProxy::getFor()` to fail gracefully:

```
$proxy = AccessorProxy::getFor($target);
if (!$proxy) {
    // target does not support accessors
}
```

📖 See [docs/AccessorProxy.md](docs/AccessorProxy.md) for full reference.

---

### ⚠️ Exceptions &amp; Message IDs

[](#️-exceptions--message-ids)

Exceptions are structured for i18n-ready messages and configuration errors:

- `AccessorException` — runtime access errors (missing resolver/getter/setter).
- `PropAccessConfigException` — boot/config misuse (e.g. read-only writes).

`AccessorException` uses message IDs as templates plus parameters for translation:

```
use Nandan108\PropAccess\Exception\DefaultMessageMap;

$id = 'prop_access.getter_not_found';
$english = DefaultMessageMap::MESSAGES[$id];
```

---

### ✅ Quality

[](#-quality)

- ✅ 100% test coverage
- ✅ Psalm level 1
- ✅ Zero dependencies

---

MIT License © [nandan108](https://github.com/nandan108)

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance83

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity41

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

Recently: every ~61 days

Total

8

Last Release

85d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/024c3beb5cbe22cd3e3f3db6938cf893c09d0b3b90076e2e1566530cd0693372?d=identicon)[Nandan108](/maintainers/Nandan108)

---

Top Contributors

[![Nandan108](https://avatars.githubusercontent.com/u/354944?v=4)](https://github.com/Nandan108 "Nandan108 (11 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/nandan108-prop-access/health.svg)

```
[![Health](https://phpackages.com/badges/nandan108-prop-access/health.svg)](https://phpackages.com/packages/nandan108-prop-access)
```

###  Alternatives

[lorisleiva/lody

Load files and classes as lazy collections in Laravel.

956.6M9](/packages/lorisleiva-lody)[nordcoders/laravel-service-maker

Generate services and contracts in Laravel with the artisan command

261.4k](/packages/nordcoders-laravel-service-maker)

PHPackages © 2026

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