PHPackages                             yzen.dev/plain-to-class - 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. yzen.dev/plain-to-class

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

yzen.dev/plain-to-class
=======================

Class-transformer to transform your dataset into a structured object

3.0.5(2y ago)16293.9k↓28.6%7[1 PRs](https://github.com/yzen-dev/plain-to-class/pulls)6MITPHPPHP ^8.0

Since Mar 17Pushed 1y ago2 watchersCompare

[ Source](https://github.com/yzen-dev/plain-to-class)[ Packagist](https://packagist.org/packages/yzen.dev/plain-to-class)[ RSS](/packages/yzendev-plain-to-class/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (7)Versions (26)Used By (6)

ClassTransformer
----------------

[](#classtransformer)

[![Packagist Version](https://camo.githubusercontent.com/484f940d761e4a2c8741ab2e38fe6ee857e2d0d6ac24ac656b1407a516d58209/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f797a656e2e6465762f706c61696e2d746f2d636c6173733f636f6c6f723d626c7565266c6162656c3d76657273696f6e)](https://camo.githubusercontent.com/484f940d761e4a2c8741ab2e38fe6ee857e2d0d6ac24ac656b1407a516d58209/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f797a656e2e6465762f706c61696e2d746f2d636c6173733f636f6c6f723d626c7565266c6162656c3d76657273696f6e)[![GitHub Workflow Status (with branch)](https://camo.githubusercontent.com/5255640f66d85e8c5cece910af399fa94858bd0ab6086a9f5c241c7b9777af96/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f797a656e2d6465762f706c61696e2d746f2d636c6173732f74657374732e796d6c3f6272616e63683d6d6173746572)](https://camo.githubusercontent.com/5255640f66d85e8c5cece910af399fa94858bd0ab6086a9f5c241c7b9777af96/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f797a656e2d6465762f706c61696e2d746f2d636c6173732f74657374732e796d6c3f6272616e63683d6d6173746572)[![Coverage](https://camo.githubusercontent.com/6a8febe2528907db6ec59f14183c24db60db04539c6d933ef3f9768231358c4a/68747470733a2f2f636f6465636f762e696f2f67682f797a656e2d6465762f706c61696e2d746f2d636c6173732f6272616e63682f6d61737465722f67726170682f62616467652e7376673f746f6b656e3d51414f3853544c504d49)](https://codecov.io/gh/yzen-dev/plain-to-class)[![License](https://camo.githubusercontent.com/ff05189e8df875746311b14adeaf6fce1e4d588641dfe6a7094214f459afae49/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f797a656e2d6465762f706c61696e2d746f2d636c617373)](https://camo.githubusercontent.com/ff05189e8df875746311b14adeaf6fce1e4d588641dfe6a7094214f459afae49/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f797a656e2d6465762f706c61696e2d746f2d636c617373)[![readthedocs](https://camo.githubusercontent.com/0a02e64ba634830670a13e303d61424f9374ac26aceae39e891c6aa3f8faddb1/68747470733a2f2f696d672e736869656c64732e696f2f72656164746865646f63732f706c61696e2d746f2d636c617373)](https://camo.githubusercontent.com/0a02e64ba634830670a13e303d61424f9374ac26aceae39e891c6aa3f8faddb1/68747470733a2f2f696d672e736869656c64732e696f2f72656164746865646f63732f706c61696e2d746f2d636c617373)[![Packagist Downloads](https://camo.githubusercontent.com/4be52d215a4d5b2521370c03ad505f0ac2893d4e801d9249232b08066afa2d7d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f797a656e2e6465762f706c61696e2d746f2d636c617373)](https://camo.githubusercontent.com/4be52d215a4d5b2521370c03ad505f0ac2893d4e801d9249232b08066afa2d7d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f797a656e2e6465762f706c61696e2d746f2d636c617373)[![Packagist Downloads](https://camo.githubusercontent.com/4d8430c195d2f4ea21dd9d2395d3d80c07f171f73eb3a0711d982359299d3f44/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f797a656e2e6465762f706c61696e2d746f2d636c617373)](https://camo.githubusercontent.com/4d8430c195d2f4ea21dd9d2395d3d80c07f171f73eb3a0711d982359299d3f44/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f797a656e2e6465762f706c61696e2d746f2d636c617373)

[![Mutation testing badge](https://camo.githubusercontent.com/7c7b21df5ad3e1128d05f64ac8affc7b4c13fccd4979b6610a5ba0592256cd56/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f7374796c653d666c61742675726c3d687474707325334125324625324662616467652d6170692e737472796b65722d6d757461746f722e696f2532466769746875622e636f6d253246797a656e2d646576253246706c61696e2d746f2d636c6173732532466d6173746572)](https://dashboard.stryker-mutator.io/reports/github.com/yzen-dev/plain-to-class/master)[![type-coverage](https://camo.githubusercontent.com/c24710a5b3f8ce31f819ac90b9f7fc7fce09a4b96afa61e60a7cdc1015f75faf/68747470733a2f2f73686570686572642e6465762f6769746875622f797a656e2d6465762f706c61696e2d746f2d636c6173732f636f7665726167652e737667)](https://shepherd.dev/github/yzen-dev/plain-to-class)[![psalm-level](https://camo.githubusercontent.com/977e26754a486f7ed191fd2c0b13a5221ddf4900c1d644bada993d0cad40d1cc/68747470733a2f2f73686570686572642e6465762f6769746875622f797a656e2d6465762f706c61696e2d746f2d636c6173732f6c6576656c2e737667)](https://shepherd.dev/github/yzen-dev/plain-to-class)

> Alas, I do not speak English, and the documentation was compiled through google translator :( I will be glad if you can help me describe the documentation more correctly :)

This library will allow you to easily convert any data set into the object you need. You are not required to change the structure of classes, inherit them from external modules, etc. No dancing with tambourines - just data and the right class.

It is considered good practice to write code independent of third-party packages and frameworks. The code is divided into services, domain zones, various layers, etc.

To transfer data between layers, the **DataTransfer Object** (DTO) template is usually used. A DTO is an object that is used to encapsulate data and send it from one application subsystem to another.

Thus, services/methods work with a specific object and the data necessary for it. At the same time, it does not matter where this data was obtained from, it can be an http request, a database, a file, etc.

Accordingly, each time the service is called, we need to initialize this DTO. But it is not effective to compare data manually each time, and it affects the readability of the code, especially if the object is complex.

This is where this package comes to the rescue, which takes care of all the work with mapping and initialization of the necessary DTO.

[Documentation](https://plain-to-class.readthedocs.io)

- [Installation](#Installation)
- [Usage](#Usage)
    - [Collection](#Collection)
    - [Anonymous array](#anonymous-array)
    - [Writing style](#writing-style)
    - [Alias](#alias)
    - [Custom setter](#custom-setter)
    - [After Transform](#after-transform)
    - [Custom transform](#custom-transform)
    - [Comparison](#Comparison)
    - [Cache](#Cache)

**Installation**
----------------

[](#installation)

The package can be installed via composer:

```
composer require yzen.dev/plain-to-class

```

> Note: The current version of the package supports only PHP 8.0 +.

> For PHP version 7.4, you can read the documentation in [version v0.\*](https://github.com/yzen-dev/plain-to-class/tree/php-7.4).

**Usage**
---------

[](#usage)

Common use case:

### **Base**

[](#base)

```
namespace DTO;

class CreateUserDTO
{
    public string $email;
    public float $balance;
}
```

```
$data = [
    'email' => 'test@mail.com',
    'balance' => 128.41,
];

$dto = (new Hydrator())->create(CreateUserDTO::class, $data);
// or static init
$dto = Hydrator::init()->create(CreateUserDTO::class, $data);
var_dump($dto);
```

Result:

```
object(\CreateUserDTO)
  'email' => string(13) "test@mail.com"
  'balance' => float(128.41)
```

Also for php 8 you can pass named arguments:

```
$dto = Hydrator::init()->create(CreateUserDTO::class,
        email: 'test@mail.com',
        balance: 128.41
      );
```

If the property is not of a scalar type, but a class of another DTO is allowed, it will also be automatically converted.

```
class ProductDTO
{
    public int $id;
    public string $name;
}

class PurchaseDTO
{
    public ProductDTO $product;
    public float $cost;
}

$data = [
    'product' => ['id' => 1, 'name' => 'phone'],
    'cost' => 10012.23,
];

$purchaseDTO = Hydrator::init()->create(PurchaseDTO::class, $data);
var_dump($purchaseDTO);
```

Output:

```
object(PurchaseDTO)
  public ProductDTO 'product' =>
    object(ProductDTO)
      public int 'id' => int 1
      public string 'name' => string 'phone' (length=5)
  public float 'cost' => float 10012.23
```

### **Collection**

[](#collection)

If you have an array of objects of a certain class, then you must specify the ConvertArray attribute for it, passing it to which class you need to bring the elements.

You can also specify a class in PHP DOC, but then you need to write the full path to this class `array `. This is done in order to know exactly which instance you need to create. Since Reflection does not provide out-of-the-box functions for getting the `use *` file. Besides `use *`, you can specify an alias, and it will be more difficult to trace it. Example:

```
class ProductDTO
{
    public int $id;
    public string $name;
}

class PurchaseDTO
{
    #[ConvertArray(ProductDTO::class)]
    public array $products;
}

$data = [
    'products' => [
        ['id' => 1, 'name' => 'phone',],
        ['id' => 2, 'name' => 'bread',],
    ],
];
$purchaseDTO = Hydrator::init()->create(PurchaseDTO::class, $data);
```

### **Anonymous array**

[](#anonymous-array)

In case you need to convert an array of data into an array of class objects, you can implement this using the `transformCollection` method.

```
$data = [
  ['id' => 1, 'name' => 'phone'],
  ['id' => 2, 'name' => 'bread'],
];
$products = Hydrator::init()->createCollection(ProductDTO::class, $data);
```

As a result of this execution, you will get an array of ProductDTO objects

```
array(2) {
  [0]=>
      object(ProductDTO) {
        ["id"]=> int(1)
        ["name"]=> string(5) "phone"
      }
  [1]=>
      object(ProductDTO) {
        ["id"]=> int(2)
        ["name"]=> string(5) "bread"
      }
}
```

You may also need a piecemeal transformation of the array. In this case, you can pass an array of classes, which can then be easily unpacked.

```
    $userData = ['id' => 1, 'email' => 'test@test.com', 'balance' => 10012.23];
    $purchaseData = [
        'products' => [
            ['id' => 1, 'name' => 'phone',],
            ['id' => 2, 'name' => 'bread',],
        ],
        'user' => ['id' => 3, 'email' => 'fake@mail.com', 'balance' => 10012.23,],
    ];

    $result = Hydrator::init()->createMultiple([UserDTO::class, PurchaseDTO::class], [$userData, $purchaseData]);

    [$user, $purchase] = $result;
    var_dump($user);
    var_dump($purchase);
```

Result:

```
object(UserDTO) (3) {
  ["id"] => int(1)
  ["email"]=> string(13) "test@test.com"
  ["balance"]=> float(10012.23)
}

object(PurchaseDTO) (2) {
  ["products"]=>
  array(2) {
    [0]=>
    object(ProductDTO)#349 (3) {
      ["id"]=> int(1)
      ["name"]=> string(5) "phone"
    }
    [1]=>
    object(ProductDTO)#348 (3) {
      ["id"]=> int(2)
      ["name"]=> string(5) "bread"
    }
  }
  ["user"]=>
  object(UserDTO)#332 (3) {
    ["id"]=> int(3)
    ["email"]=> string(13) "fake@mail.com"
    ["balance"]=> float(10012.23)
  }
}
```

### **Writing style**

[](#writing-style)

A constant problem with the style of writing, for example, in the database it is snake\_case, and in the camelCase code. And they constantly need to be transformed somehow. The package takes care of this, you just need to specify the WritingStyle attribute on the property:

```
class WritingStyleSnakeCaseDTO
{
    #[WritingStyle(WritingStyle::STYLE_CAMEL_CASE, WritingStyle::STYLE_SNAKE_CASE)]
    public string $contact_fio;

    #[WritingStyle(WritingStyle::STYLE_CAMEL_CASE)]
    public string $contact_email;
}

 $data = [
  'contactFio' => 'yzen.dev',
  'contactEmail' => 'test@mail.com',
];
$model = Hydrator::init()->create(WritingStyleSnakeCaseDTO::class, $data);
var_dump($model);
```

```
RESULT:

object(WritingStyleSnakeCaseDTO) (2) {
  ["contact_fio"]=> string(8) "yzen.dev"
  ["contact_email"]=> string(13) "test@mail.com"
}
```

### **Alias**

[](#alias)

Various possible aliases can be set for the property, which will also be searched in the data source. This can be useful if the DTO is generated from different data sources.

```
class WithAliasDTO
{
    #[FieldAlias('userFio')]
    public string $fio;

    #[FieldAlias(['email', 'phone'])]
    public string $contact;
}
```

### **Custom setter**

[](#custom-setter)

If a field requires additional processing during its initialization, you can mutator. To define a mutator, define a set{Attribute}Attribute method on your class where {Attribute} is cased name of the property you wish to access. This mutator will be automatically called when we attempt to set the value of the real\_address attribute on the model:

```
class UserDTO
{
    public int $id;
    public string $real_address;

    public function setRealAddressAttribute(string $value)
    {
        $this->real_address = strtolower($value);
    }
}
```

### **After Transform**

[](#after-transform)

Inside the class, you can create the `afterTransform` method, which will be called immediately after the conversion is completed. In it, we can describe our additional verification or transformation logic by already working with the state of the object.

```
class UserDTO
{
    public int $id;
    public float $balance;

    public function afterTransform()
    {
        $this->balance = 777;
    }
}
```

### **Custom transform**

[](#custom-transform)

If you need to completely transform yourself, then you can create a transform method in the class. In this case, no library processing is called, all the responsibility of the conversion passes to your class.

```
class CustomTransformUserDTOArray
{
    public string $email;
    public string $username;

    public function transform($args)
    {
        $this->email = $args['login'];
        $this->username = $args['fio'];
    }
}
```

### **Cache**

[](#cache)

The package supports a class caching mechanism to avoid the cost of reflection. This functionality is recommended to be used only if you have very voluminous classes, or there is a cyclic transformation of multiple entities. On ordinary lightweight DTO, there will be only 5-10%, and this will be unnecessary access in the file system.

You can enable caching by passing the config to the hydrator constructor:

```
(new Hydrator(new HydratorConfig(true)))
    ->create(PurchaseDto::class, $data);
```

### Comparison

[](#comparison)

I also made a comparison with current analogues and here are the main disadvantages

- Works only for a specific framework
- Force to inherit or change your current class structure
- Conversion takes longer

Below is an example of my benchmark comparison

[![image](https://user-images.githubusercontent.com/24630195/216361904-e2cf5674-071b-4e3e-9ecd-937f88c472f5.png)](https://user-images.githubusercontent.com/24630195/216361904-e2cf5674-071b-4e3e-9ecd-937f88c472f5.png)

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance27

Infrequent updates — may be unmaintained

Popularity47

Moderate usage in the ecosystem

Community21

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 94.9% 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 ~46 days

Recently: every ~38 days

Total

22

Last Release

916d ago

Major Versions

0.4.0 → 1.1.12022-03-13

0.4.1 → 1.1.22022-03-14

0.4.2 → 1.1.32022-03-14

1.2 → 2.02023-02-02

2.0 → 3.02023-06-15

PHP version history (7 changes)0.0.1PHP ^5.5|^7.0|^8.0

0.1.0PHP 7.4

0.1.1PHP ^7.4

0.3.0PHP ^7.4 || ^8.0

1.0PHP ^8.0

0.4.0PHP ^7.4|^8.0

3.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/8ca07942b4d955ee72b1bc92220b1bc7686708d0f109ee4abf81f8fbd30732c3?d=identicon)[yzen.dev](/maintainers/yzen.dev)

---

Top Contributors

[![yzen-dev](https://avatars.githubusercontent.com/u/24630195?v=4)](https://github.com/yzen-dev "yzen-dev (111 commits)")[![volodymyr-hordiienko](https://avatars.githubusercontent.com/u/2478722?v=4)](https://github.com/volodymyr-hordiienko "volodymyr-hordiienko (5 commits)")[![pies](https://avatars.githubusercontent.com/u/37940?v=4)](https://github.com/pies "pies (1 commits)")

---

Tags

class-transformerconvertdatasetphpphpconvertclassobjecttransformerclass-transformer

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/yzendev-plain-to-class/health.svg)

```
[![Health](https://phpackages.com/badges/yzendev-plain-to-class/health.svg)](https://phpackages.com/packages/yzendev-plain-to-class)
```

PHPackages © 2026

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