PHPackages                             dashifen/data-transfer-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. dashifen/data-transfer-object

ActiveLibrary

dashifen/data-transfer-object
=============================

An object that exists to transfer data.

1.2.1(1y ago)011WTFPLPHPPHP &gt;=8.4

Since Mar 9Pushed 1y ago1 watchersCompare

[ Source](https://github.com/dashifen/data-transfer-object)[ Packagist](https://packagist.org/packages/dashifen/data-transfer-object)[ RSS](/packages/dashifen-data-transfer-object/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (2)Versions (6)Used By (0)

Data Transfer Object
====================

[](#data-transfer-object)

A data transfer object (DTO) is an object that takes information from one place and moves it to another. Frequently, I use these to avoid having to pass arrays around because my IDE (and many others) can provide code hinting for objects but may struggle to do so for arrays.

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

[](#installation)

`composer require dashifen/data-transfer-object`

Usage
-----

[](#usage)

There are two ways to use my DTO objects:

1. Extending the `AbstractDTO` object, or
2. Extending the `DTO` object.

In either case, instantiating a DTO requires an associative array as an argument to its constructor. That array should be a map linking property names to their values. For example:

```
class FooBar extends DTO {
  protected(set) int $foo;
  protected(set) int $bar;
}

$example = new FooBar(['foo' => 1, 'bar' => 2]);
```

The constructor will then assign the value 1 to the foo property and 2 to bar.

### Extending AbstractDTO

[](#extending-abstractdto)

The `AbstractDTO` object requires that you implement a `toArray` method for yourself. It also throws a `DTOException` from its constructor if there are unmet requirements (see below).

### Extending DTO

[](#extending-dto)

The `DTO` object is, itself, an extension of the `AbstractDTO`. It does two things for you:

1. Catches the `DTOException` thrown in the constructor and uses the `catcher` method of the `DebuggingTrait` to handle it.
2. Implements the `toArray` method returning an array of any properties that are publicly available, even if asymmetrically so or [virtual](https://www.php.net/manual/en/language.oop5.property-hooks.php#language.oop5.property-hooks.virtual).

Asymmetric Visibility
---------------------

[](#asymmetric-visibility)

In PHP 8.4, [asymmetric visibility](https://www.php.net/manual/en/language.oop5.visibility.php#language.oop5.visibility-members-aviz) allows us to create properties that can be accessed publicly but set only within the class.

Both properties with `public` and `protected(set)` visibility can be set via the constructor in the `AbstractDTO` object even within your extensions. If you want to use `private(set)` visibility, you'll need to override it because private setters are only scoped within their own object and neither in ancestors nor children.

Required Properties
-------------------

[](#required-properties)

If there are properties that should be required, i.e. that must be set in your object's constructor, specify them by name as a protected array of requirements in its definition:

```
class FooBar extends DTO {
  protected array $requirements = ['foo'];
  protected(set) int $foo;
  protected(set) int $bar;
}
```

Getters and Setters
-------------------

[](#getters-and-setters)

I recommend specifying both getters and setters using property hooks:

```
class Example extends DTO {
  protected(set) string $usPhone {
    set {
      $this->usPhone = preg_replace('~\D~', '', $value);
    }

    get {
      return vsprintf('+1 (%s) %s-%s', [
        substr($this->usPhone, 0, 3),
        substr($this->usPhone, 3, 3),
        substr($this->usPhone, 6),
      ]);
    }
  }
}
```

Repositories
------------

[](#repositories)

These are the successors to my so-called [repository](https://github.com/dashifen/repository) object. With the release of 8.4 and both property hooks and asymmetric property visibility, the work that my repository objects was doing to produce properties that could be publicly read but set only with an object (and, perhaps, only once) is unnecessary.

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance45

Moderate activity, may be stable

Popularity5

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity59

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

Total

4

Last Release

428d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/8269?v=4)[David Dashifen Kees](/maintainers/dashifen)[@dashifen](https://github.com/dashifen)

---

Top Contributors

[![dashifen](https://avatars.githubusercontent.com/u/8269?v=4)](https://github.com/dashifen "dashifen (8 commits)")

### Embed Badge

![Health badge](/badges/dashifen-data-transfer-object/health.svg)

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

###  Alternatives

[dashifen/wp-handler

An object to define handlers for various WordPress action and filter hooks using protected methods.

205.5k5](/packages/dashifen-wp-handler)

PHPackages © 2026

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