PHPackages                             oihana/php-reflect - 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. oihana/php-reflect

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

oihana/php-reflect
==================

The Oihana PHP Reflection library

1.1.0(3w ago)01.1k17MPL-2.0PHPPHP &gt;=8.4CI passing

Since Aug 13Pushed 2w agoCompare

[ Source](https://github.com/BcommeBois/oihana-php-reflect)[ Packagist](https://packagist.org/packages/oihana/php-reflect)[ Docs](https://github.com/BcommeBois/oihana-php-reflect)[ RSS](/packages/oihana-php-reflect/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (10)Versions (6)Used By (17)

Oihana PHP - Reflect
====================

[](#oihana-php---reflect)

[![Oihana PHP - Reflect](https://raw.githubusercontent.com/BcommeBois/oihana-php-reflect/main/assets/images/oihana-php-reflect-logo-inline-512x160.png)](https://raw.githubusercontent.com/BcommeBois/oihana-php-reflect/main/assets/images/oihana-php-reflect-logo-inline-512x160.png)

[![Latest Version](https://camo.githubusercontent.com/9588c9d7bf048f41b684031e205eb7944b1ca457ebe07bb78f672fbf5bf58305/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f6968616e612f7068702d7265666c6563742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/oihana/php-reflect)[![Total Downloads](https://camo.githubusercontent.com/7de70fb04a555cd19272812d423b411f27f324b317be0c196fbd100536a78ead/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6f6968616e612f7068702d7265666c6563742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/oihana/php-reflect)[![License](https://camo.githubusercontent.com/b2fab91aeef1ea27a23a9d5ccd3c4289c7328c47417e41083f8636b62b47017f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6f6968616e612f7068702d7265666c6563742e7376673f7374796c653d666c61742d737175617265)](LICENSE)

Lightweight reflection and hydration helpers for modern PHP, part of the Oihana PHP ecosystem.

It provides:

- Friendly wrappers around PHP's Reflection API
- Array-to-object hydration with attribute-based mapping
- Utilities to expose public properties as arrays
- Simple constant “enums” helpers
- A compact `Version` value object

📚 Documentation
---------------

[](#-documentation)

Full documentation: `https://bcommebois.github.io/oihana-php-reflect`

📦 Installation
--------------

[](#-installation)

Requires PHP 8.4+

```
composer require oihana/php-reflect
```

✨ Features
----------

[](#-features)

Reflection helpers

- List constants, methods, properties with visibility filters
- Inspect method parameters: type, default, nullable, optional, variadic
- Inspect classes/properties: `hasMethod`, `hasProperty`, `propertyType`, `namespace` (union types rendered as `A|B`, intersection as `A&B`)
- Read instantiated attributes: `classAttributes`, `propertyAttributes`, `methodAttributes` (optionally filtered by attribute class)
- Describe any callable’s parameters (`describeCallableParameters`)
- Cached `ReflectionClass` instances

Hydration

- Instantiate and hydrate objects from associative arrays (recursively)
- Supports union types and nullability
- Attribute-based mapping:
    - `#[HydrateKey('source_key')]` to rename incoming keys (accepts several fallback keys: `#[HydrateKey('user_name', 'username')]` — first present wins)
    - `#[HydrateWith(Foo::class, Bar::class)]` for arrays of objects, including polymorphism via `@type`/`type` or property-guessing
    - `#[HydrateAs(Foo::class)]` to override ambiguous types (`object`, `array`, `mixed`, unions)
    - `#[Transient]` (or its alias `#[HydrateIgnore]`) to exclude a public property from both hydration (input) and `toArray()` (output) — e.g. computed/derived properties
- PHPDoc `@var Type[]` and `@var array` support for array element types
- Backed enums: scalar values are resolved to enum cases via `Enum::from()` (single values, and arrays of enums via `#[HydrateWith]` or `@var Enum[]`). Pure (non-backed) enums have no scalar representation: hydrating one from a scalar throws an `InvalidArgumentException` — declare a backed enum instead
- `DateTimeInterface`: scalar values are resolved to date instances (string → parsed date, int → Unix timestamp). In a union with a scalar (e.g. `string|DateTimeInterface`), the raw value is kept unless `#[HydrateAs(DateTimeImmutable::class)]` forces the conversion
- Classes with a required constructor: instantiated via `newInstanceWithoutConstructor()` and populated from the data (a no-argument-callable constructor is still invoked normally)
- `readonly` and asymmetric-visibility properties (`public private(set)` / `public protected(set)`, PHP 8.4): values are assigned via reflection, so they are initialized correctly (scalar coercion preserved)
- Scalar coercion: values are converted to the declared scalar type following PHP's coercive typing (`'42'` → `int 42`, `7` → `string '7'`); a value that cannot be coerced raises a `HydrationException` (independent of `strict_types`)
- Error handling: every hydration failure throws a single catchable `HydrationException` (extends `InvalidArgumentException`), exposing `getClassName()`, `getPropertyName()` and the original error via `getPrevious()` — handy to skip an invalid record when hydrating a batch/stream
- Symmetric serialization: `ReflectionTrait::toArray()` serializes `DateTimeInterface` values to ISO 8601 (overridable), and can emit `#[HydrateKey]` source keys (opt-in via `SerializeOption`) — round-trip with `hydrate()`
- Performance: a per-class **hydration plan** is cached on first use, so the data-independent reflection work (attributes, `@var` item types, constructor strategy, builtin types) is computed once and reused for every object of that class. The cache is in-memory, bounded by the number of hydrated classes, and needs no eviction. On nested documents this cuts hydration time by roughly a third (the deeper the nesting, the larger the gain)

Traits

- `ReflectionTrait` convenience layer and `jsonSerializeFromPublicProperties()` (with optional reduction)
- `ConstantsTrait` utilities over class constants: `getAll`, `includes`, `enums`, `getConstant`, `validate`

Value objects

- `Version` packs major/minor/build/revision into a 32-bit int with configurable string output

🚀 Quick start
-------------

[](#-quick-start)

### Reflection basics

[](#reflection-basics)

```
use oihana\reflect\Reflection;

$ref = new Reflection();

// Constants
$constants = $ref->constants(MyEnum::class); // ['ACTIVE' => 'active']

// Methods / Properties
$methods = $ref->methods(MyClass::class);
$props   = $ref->properties(MyDto::class);

// Parameters inspection
$type     = $ref->parameterType(MyClass::class, 'setName', 'name'); // 'string'
$default  = $ref->parameterDefaultValue(MyClass::class, 'setAge', 'age'); // 30
$nullable = $ref->isParameterNullable(MyClass::class, 'setNickname', 'nickname'); // true
```

### Describe any callable

[](#describe-any-callable)

```
$fn = fn(string $name, int $age = 42, ...$tags) => null;
$params = (new Reflection())->describeCallableParameters($fn);
/*
[
  ['name' => 'name', 'type' => 'string', 'optional' => false, 'nullable' => false, 'variadic' => false],
  ['name' => 'age',  'type' => 'int',    'optional' => true,  'nullable' => false, 'variadic' => false, 'default' => 42],
  ['name' => 'tags', 'type' => null,     'optional' => false, 'nullable' => false, 'variadic' => true],
]
*/
```

### Hydration: flat and nested

[](#hydration-flat-and-nested)

```
class Address { public string $city; }
class User { public string $name; public ?Address $address = null; }

$data = ['name' => 'Alice', 'address' => ['city' => 'Paris']];
$user = (new Reflection())->hydrate($data, User::class);
```

### Hydration with attributes

[](#hydration-with-attributes)

```
use oihana\reflect\attributes\{HydrateKey, HydrateWith, HydrateAs};

class WithKey { #[HydrateKey('user_name')] public string $name; }
// Maps input key 'user_name' to property 'name'

class Geo { #[HydrateWith(Address::class)] public array $locations = []; }
// Hydrates each element of an array property as Address

class Wrapper { #[HydrateAs(Address::class)] public object $payload; }
// Overrides ambiguous type (object/array/mixed/union)
```

### Arrays of objects via PHPDoc

[](#arrays-of-objects-via-phpdoc)

```
class Address { public string $city; }
class Geo { /** @var Address[] */ public array $locations = []; }

$geo = (new Reflection())->hydrate(
  ['locations' => [ ['city' => 'Lyon'], ['city' => 'Nice'] ]],
  Geo::class
);
```

### Polymorphic arrays with HydrateWith

[](#polymorphic-arrays-with-hydratewith)

```
class A { public string $type = 'A'; }
class B { public string $type = 'B'; }
class Box { #[HydrateWith(A::class, B::class)] public array $items = []; }

// Chooses the right class using '@type' or 'type', or best-guess by properties
```

### Trait: ReflectionTrait

[](#trait-reflectiontrait)

```
use oihana\reflect\traits\ReflectionTrait;

class Product {
    use ReflectionTrait;
    public string $name = 'Book';
    public ?string $desc = null;
}

$p = new Product();
$data = $p->jsonSerializeFromPublicProperties(Product::class, true); // ['name' => 'Book']
```

### Trait: ConstantsTrait

[](#trait-constantstrait)

```
use oihana\reflect\traits\ConstantsTrait;

final class Status { use ConstantsTrait; public const string OPEN = 'open'; public const string CLOSED = 'closed'; }

Status::includes('open'); // true
Status::enums();           // ['closed', 'open'] (sorted unique values)
Status::getConstant('open'); // 'OPEN'
```

### Value object: Version

[](#value-object-version)

```
use oihana\reflect\Version;

$v = new Version(1, 2, 3, 4);
$v->fields = 3;            // print as 1.2.3
echo (string) $v;          // "1.2.3"
$v->major = 2;             // mutate safely
$n = $v->valueOf();        // packed 32-bit int
```

✅ Running Unit Tests
--------------------

[](#-running-unit-tests)

```
composer test
```

Run a specific test file:

```
composer test ./tests/oihana/reflect/VersionTest.php
```

🛠️ Generate the API Docs
------------------------

[](#️-generate-the-api-docs)

We use phpDocumentor to generate the HTML docs into `./docs`.

```
composer doc
```

🧾 License
---------

[](#-license)

Licensed under the Mozilla Public License 2.0 (MPL-2.0). See `LICENSE`.

👤 Author
--------

[](#-author)

- Author: Marc ALCARAZ (aka eKameleon)
- Email:
- Website: `http://www.ooop.fr`

###  Health Score

50

↑

FairBetter than 95% of packages

Maintenance96

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community17

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

Total

5

Last Release

24d ago

### Community

Maintainers

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

---

Top Contributors

[![ekameleon](https://avatars.githubusercontent.com/u/749032?v=4)](https://github.com/ekameleon "ekameleon (80 commits)")

---

Tags

phpreflectionhydratation

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/oihana-php-reflect/health.svg)

```
[![Health](https://phpackages.com/badges/oihana-php-reflect/health.svg)](https://phpackages.com/packages/oihana-php-reflect)
```

###  Alternatives

[minime/annotations

The KISS PHP annotations library

233390.7k38](/packages/minime-annotations)

PHPackages © 2026

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