PHPackages                             sunrise/hydrator - 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. sunrise/hydrator

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

sunrise/hydrator
================

Strictly typed object hydration and value casting.

v3.20.1(2w ago)2134.7k↓13.1%2[1 issues](https://github.com/sunrise-php/hydrator/issues)4MITPHPPHP &gt;=7.4

Since Mar 26Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/sunrise-php/hydrator)[ Packagist](https://packagist.org/packages/sunrise/hydrator)[ Docs](https://github.com/sunrise-php/hydrator)[ RSS](/packages/sunrise-hydrator/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (10)Dependencies (31)Versions (64)Used By (4)

Strictly typed object hydration and value casting
=================================================

[](#strictly-typed-object-hydration-and-value-casting)

[![Scrutinizer Code Quality](https://camo.githubusercontent.com/291fb56ba88d85a3c17c1973294bfad83b5dd63449fd881ea8a831488b9fd874/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f73756e726973652d7068702f6879647261746f722f6261646765732f7175616c6974792d73636f72652e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/sunrise-php/hydrator/?branch=main)[![Code Coverage](https://camo.githubusercontent.com/38b63e7c5c05fdf0f7a21de9bc664eb0c08da23c33f51f7c713c991d0eb25392/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f73756e726973652d7068702f6879647261746f722f6261646765732f636f7665726167652e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/sunrise-php/hydrator/?branch=main)[![Build Status](https://camo.githubusercontent.com/549337839f27b58cddeae722a8798b4c830c0d471eb33c900917b4c80e65e9a9/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f73756e726973652d7068702f6879647261746f722f6261646765732f6275696c642e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/sunrise-php/hydrator/build-status/main)[![Code Intelligence Status](https://camo.githubusercontent.com/59fe75d9f107a0a84e90efcf37960bf0a0fd484965c2e09f66ba5b2198815041/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f73756e726973652d7068702f6879647261746f722f6261646765732f636f64652d696e74656c6c6967656e63652e7376673f623d6d61696e)](https://scrutinizer-ci.com/code-intelligence)

🇬🇧 **English version** | [🇷🇺 Русская версия](README-ru.md)

The package hydrates object properties from arrays and JSON with casting to declared PHP types. Individual values can also be cast without hydrating an object.

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

[](#installation)

```
composer require sunrise/hydrator
```

The package supports PHP 7.4 and newer. Examples in this README target PHP 8+.

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

[](#quick-start)

```
use Sunrise\Hydrator\Annotation\Filter;
use Sunrise\Hydrator\Annotation\ItemType;
use Sunrise\Hydrator\Hydrator;

final class CreateUserRequest
{
    #[Filter('trim')]
    public string $email;

    public bool $isActive;

    #[ItemType('string', limit: 10)]
    public array $roles = [];
}

$request = (new Hydrator())->hydrate(CreateUserRequest::class, [
    'email' => ' user@example.com ',
    'isActive' => 'true',
    'roles' => ['user', 'editor'],
]);
```

The hydrator:

- creates an object without calling its constructor or fills an existing object;
- skips properties marked with `#[Ignore]`;
- ignores input keys that do not match any property;
- hydrates nested objects recursively;
- collects property and element hydration errors into one `InvalidDataException`.

An input value is required when the corresponding property is not initialized and no default value is defined for it. A default value can be defined in the property declaration, in the constructor parameter with the same name, or through `#[DefaultValue]`.

Default values are used only when the input key is missing. A passed `null` is treated as an input value and is validated against the property type.

### Hydration from JSON

[](#hydration-from-json)

```
$request = (new Hydrator())->hydrateWithJson(
    CreateUserRequest::class,
    '{"email":"user@example.com","isActive":true}'
);
```

The root JSON value must be an object or an array.

### Value Casting

[](#value-casting)

```
use Sunrise\Hydrator\Dictionary\BuiltinType;
use Sunrise\Hydrator\Hydrator;
use Sunrise\Hydrator\Type;

$value = (new Hydrator())->castValue(
    '42',
    Type::fromName(BuiltinType::INT)
);
```

Supported Types
---------------

[](#supported-types)

PHP typeAccepted input values`mixed`Any value`bool``bool` or the strings `1`, `0`, `true`, `false`, `yes`, `no`, `on`, `off``int``int` or a string representation of an integer`float``float`, `int`, or a string representation of a number`string``string` or `int``array``array` or `stdClass``DateTimeImmutable` and subclassesA string in the configured format; an integer or string for format `U``DateInterval`A string accepted by the `DateInterval` constructor`DateTimeZone`A timezone identifierA concrete backed enumA value of the corresponding backing type; for `int`, a string representation of an integer is also acceptedAn instantiable user-defined class`array` or `stdClass`A class implementing `ArrayAccess``array` or `stdClass`Also supported:

TypePackageA subclass of `MyCLabs\Enum\Enum``myclabs/php-enum``Ramsey\Uuid\UuidInterface``ramsey/uuid`Subclasses of `Symfony\Component\Uid\AbstractUid``symfony/uid``null` is accepted only for a type that allows `null`. For booleans, numbers, dates, intervals, timezones, enums, UUIDs, and UIDs, an empty string after trimming is treated as a missing value: `null` is returned for a nullable type; otherwise an `InvalidValueException` is thrown. Union and intersection types are not supported.

Arrays and Collections
----------------------

[](#arrays-and-collections)

`#[ItemType]` defines the type of array or collection elements and optionally limits their count:

```
use Sunrise\Hydrator\Annotation\ItemType;

final class OrderRequest
{
    #[ItemType(OrderItemRequest::class, limit: 100)]
    public array $items;
}
```

Each element will be cast to the declared type. The `allowsNull` parameter allows `null` values in elements:

```
#[ItemType('int', allowsNull: true, limit: 100)]
public array $ids;
```

For an instantiable class implementing `ArrayAccess`, the element type can also be inferred from the type of the last constructor parameter declared with `...`:

```
final class UserCollection extends ArrayObject
{
    public function __construct(User ...$users)
    {
        parent::__construct($users);
    }
}
```

The constructor is not called during hydration: the hydrator only reads the type of its last variadic parameter and creates the object without the constructor. An explicit `#[ItemType]` takes precedence over the constructor parameter type. If the collection throws `OverflowException` while adding an element, the hydrator treats it as an element limit overflow and returns an array overflow error to the user.

### Element Types from PHPDoc

[](#element-types-from-phpdoc)

The hydrator can read the element type of an `array` property from `@var`:

```
final class OrderRequest
{
    /** @var list */
    public array $items;
}

$hydrator = new Hydrator(isDocBlockReaderEnabled: true);
```

PHPDoc reading is disabled by default. `#[ItemType]` takes precedence over `@var`. `@var` is not used for classes implementing `ArrayAccess`. Use `#[ItemType]` or the type of the variadic constructor parameter instead.

Attributes
----------

[](#attributes)

AttributePurpose`#[Alias('external-name')]`Defines the input key for a property`#[Context([...])]`Defines or overrides context values for a property or parameter`#[DefaultValue(...)]`Defines a value used when the input key is missing`#[Filter(...)]`Transforms the input value before type casting`#[Format('...')]`Defines the date and time format`#[Ignore]`Excludes a property from hydration`#[ItemType(...)]`Defines the element type and maximum element count`#[Filter]` can be used more than once. Filters are applied in sequence:

```
use Sunrise\Hydrator\Annotation\Filter;

#[Filter('trim')]
#[Filter('strtolower')]
public string $email;
```

`#[Filter]` is available only on PHP 8.0 and newer.

Date, Time, and Context
-----------------------

[](#date-time-and-context)

By default, `DateTimeImmutable` uses the `DateTimeInterface::RFC3339_EXTENDED` format.

Format and timezone can be configured for a hydrator instance:

```
use DateTimeInterface;
use Sunrise\Hydrator\Dictionary\ContextKey;
use Sunrise\Hydrator\Hydrator;

$hydrator = new Hydrator(context: [
    ContextKey::TIMESTAMP_FORMAT => DateTimeInterface::RFC3339_EXTENDED,
    ContextKey::TIMEZONE => 'Europe/Belgrade',
]);
```

Operation-specific context is passed to `hydrate()` or `castValue()`. Use `#[Context]` and `#[Format]` for a property or parameter:

```
use Sunrise\Hydrator\Annotation\Context;
use Sunrise\Hydrator\Annotation\Format;
use Sunrise\Hydrator\Dictionary\ContextKey;

#[Format('Y-m-d')]
#[Context([ContextKey::TIMEZONE => 'UTC'])]
public DateTimeImmutable $date;
```

Precedence order:

1. attribute context;
2. operation context;
3. hydrator context.

Errors
------

[](#errors)

`hydrate()` collects individual value errors into `InvalidDataException`:

```
use Sunrise\Hydrator\Exception\InvalidDataException;

try {
    $request = $hydrator->hydrate(CreateUserRequest::class, $data);
} catch (InvalidDataException $e) {
    foreach ($e->getExceptions() as $error) {
        echo $error->getPropertyPath() . ': ' . $error->getMessage() . PHP_EOL;
    }
}
```

`InvalidValueException` provides:

- `getPropertyPath()` — dot-separated value path;
- `getErrorCode()` — error code;
- `getMessage()` — resolved message;
- `getMessageTemplate()` — message template;
- `getMessagePlaceholders()` — template parameters;
- `getInvalidValue()` — original value;
- `getTranslationDomain()` — translation domain.

Method exceptions:

- `hydrate()` throws `InvalidDataException` for input value errors and `InvalidObjectException` when the object cannot be created or a property has an unsupported type;
- `hydrateWithJson()` additionally uses `InvalidDataException` for JSON decoding errors and an invalid root value;
- `castValue()` throws `InvalidValueException` for a single invalid value, `InvalidDataException` for nested object or array errors, and `InvalidObjectException` for an unsupported target type.

If `symfony/validator` is installed, `InvalidValueException::getViolation()` and `InvalidDataException::getViolations()` return violations in the Symfony Validator format.

Custom Type Converters
----------------------

[](#custom-type-converters)

A converter implements `TypeConverterInterface`. If the type is not supported, the method returns without a result. If it is supported, it yields the result or throws an exception.

```
use Generator;
use Sunrise\Hydrator\Exception\InvalidValueException;
use Sunrise\Hydrator\Type;
use Sunrise\Hydrator\TypeConverterInterface;

final class MoneyTypeConverter implements TypeConverterInterface
{
    public function castValue(
        $value,
        Type $type,
        array $path,
        array $context
    ): Generator {
        if ($type->getName() !== Money::class) {
            return;
        }

        if (!is_string($value)) {
            throw InvalidValueException::mustBeString($path, $value);
        }

        yield Money::fromString($value);
    }

    public function getWeight(): int
    {
        return 100;
    }
}
```

A converter can be passed to the constructor or added later:

```
$hydrator = new Hydrator(typeConverters: [
    new MoneyTypeConverter(),
]);

$hydrator->addTypeConverter(new MoneyTypeConverter());
```

Converters are called in descending weight order. Implement `HydratorAwareInterface` or `AnnotationReaderAwareInterface` if a converter needs access to the hydrator or the annotation reader.

Compatibility
-------------

[](#compatibility)

On PHP 8.0 and newer, attributes are read automatically. On PHP 7.4, Doctrine Annotations can be used for `Alias`, `Context`, `DefaultValue`, `Format`, `Ignore`, and `ItemType`:

```
composer require doctrine/annotations
```

```
use Sunrise\Hydrator\AnnotationReader\DoctrineAnnotationReader;

$hydrator->setAnnotationReader(DoctrineAnnotationReader::default());
```

On PHP 7, only `DateTimeImmutable` itself is supported, not its subclasses. Built-in enums are supported starting with PHP 8.1.

Deprecated names `#[Subtype]` and `#[Relationship]` are kept for backward compatibility. Use `#[ItemType]` in new code.

###  Health Score

56

—

FairBetter than 97% of packages

Maintenance87

Actively maintained with recent releases

Popularity38

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity67

Established project with proven stability

 Bus Factor1

Top contributor holds 99.2% 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 ~50 days

Recently: every ~122 days

Total

40

Last Release

20d ago

Major Versions

v1.4.0 → v2.0.02021-10-22

v2.7.0 → v3.0.02023-06-08

PHP version history (2 changes)v1.0.0PHP ^7.4|^8.0

v2.6.0PHP &gt;=7.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2872934?v=4)[Anatolii Nekhai](/maintainers/fenric)[@fenric](https://github.com/fenric)

---

Top Contributors

[![fenric](https://avatars.githubusercontent.com/u/2872934?v=4)](https://github.com/fenric "fenric (131 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (1 commits)")

---

Tags

dtohydratorphphydratorhydrationtype-castingtype-conversiontype castertype converter

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sunrise-hydrator/health.svg)

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

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.7M3.4k](/packages/craftcms-cms)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.6k2.2M145](/packages/mcp-sdk)[oat-sa/tao-core

TAO core extension

64147.9k151](/packages/oat-sa-tao-core)[phpdocumentor/reflection

Reflection library to do Static Analysis for PHP Projects

12526.9M158](/packages/phpdocumentor-reflection)[symfony/ai-platform

PHP library for interacting with AI platform provider.

521.6M378](/packages/symfony-ai-platform)[cognesy/instructor-php

The complete AI toolkit for PHP: unified LLM API, structured outputs, agents, and coding agent control

326127.9k1](/packages/cognesy-instructor-php)

PHPackages © 2026

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