Creating a DTO with Traits in PHP
Tags: php, cleancode, learning, development
Published: 2023-05-02 22:30:44

Data Transfer Objects (DTOs) are an essential part of any application that deals with complex data structures. They help to encapsulate data, making it easier to manipulate and pass around between different parts of your codebase. However, creating DTOs from scratch can be a tedious and repetitive process, especially if you have many DTOs to create. Fortunately, PHP’s support for traits can help make the process much easier and less repetitive.

In this article, we’ll walk through an example of creating a UserDTO class using two traits — StaticCreateSelf and ToArray — that will help streamline the process of creating and using DTOs in your PHP applications.

## What are Traits in PHP?

Before we dive into the example, let’s quickly review what traits are in PHP. Traits are a way to reuse code in multiple classes without having to use inheritance. They allow you to define methods that can be used in multiple classes, without having to create a parent class that each class inherits from. This can be especially useful when you need to share functionality between classes that don’t have a natural parent-child relationship.

## Example: Creating a UserDTO with Traits

In this example, we’ll create a UserDTO class using two traits: StaticCreateSelf and ToArray. The StaticCreateSelf trait will provide a static _create() _method that can be used to create a new UserDTO from an array of values. The ToArray trait will provide a _toArray()_ method that will convert a UserDTO object into an associative array.

Here’s what the UserDTO class will look like:

```
    <?php
    
    declare(strict_types=1);
    
    namespace App\DTO;
    
    use App\Shared\Traits\StaticCreateSelf;
    use App\Shared\Traits\ToArray;
    
    class UserDTO
    {
        use StaticCreateSelf;
        use ToArray;
    
        public int $id;
        public string $name = '';
        public string $email = '';
    }
```

As you can see, we’ve defined the UserDTO class to have three public properties: _id_, _name_, and _email_. We've also included the StaticCreateSelf and ToArray traits using the _use_ keyword.

Let’s take a closer look at the StaticCreateSelf trait first. Here’s what it looks like:

```
    <?php
    
    declare(strict_types=1);
    
    namespace App\Shared\Traits;
    
    trait StaticCreateSelf
    {
        public static function create(array $values): self
        {
            $dto = new self();
    
            foreach ($values as $key => $value) {
                if (property_exists($dto, $key)) {
                    $dto->$key = $value;
                }
            }
    
            return $dto;
        }
    }
```

The StaticCreateSelf trait provides a _create()_ method that takes an associative array of values and returns a new instance of the class (in this case, a UserDTO). The method uses the _new self()_ expression to create a new instance of the class. It then iterates over the array of values and sets the corresponding properties on the new instance of the class.

The ToArray trait is even simpler. Here’s what it looks like:

   

```
 <?php
    
    declare(strict_types=1);
    
    namespace App\Shared\Traits;
    
    trait ToArray
    {
        public function toArray(): array
        {
            return get_object_vars($this);
        }
    }
```

The ToArray trait provides a _toArray()_ method that returns an associative array representation of the object. It does this by calling the _get_object_vars()_ function, which returns an associative array of all the object's properties and their values.

## The _UserDTO_ Class

Now that we have defined the necessary traits, we can use them to create a _UserDTO_ class. The _UserDTO_ class will define the properties of the DTO and use the _ToArray_ and _StaticCreateSelf_ traits to provide the necessary functionality. Here is the implementation of the _UserDTO_ class:

    

```
<?php
    
    declare(strict_types=1);
    
    namespace App\DTO;
    
    use App\Shared\Traits\StaticCreateSelf;
    use App\Shared\Traits\ToArray;
    
    class UserDTO
    {
        use StaticCreateSelf;
        use ToArray;
    
        public int $id;
        public string $name = '';
        public string $email = '';
    }

```
As you can see, the _UserDTO_ class uses the _StaticCreateSelf_ and _ToArray_ traits to provide the necessary functionality. The properties of the DTO are defined as public properties, which can be accessed and modified as needed.

## Using the _UserDTO_ Class

Now that we have created the _UserDTO_ class, we can use it to transfer data between different layers of our application. Here is an example of how to use the _UserDTO_ class to create a new instance of the DTO and convert it to an array:

```
    $userDTO = UserDTO::create([
        'id' => 1,
        'name' => 'John Doe',
        'email' => 'john.doe@example.com',
    ]);
    
    $userArray = $userDTO->toArray();
```

## Conclusion

DTOs are a powerful tool for improving the separation of concerns in your code and making your application more robust and maintainable. By encapsulating your data and using a DTO to transfer it between different layers, you can ensure that your application is not tightly coupled to specific data structures, making it easier to change and evolve over time.

Moreover, by using traits like _ToArray_ and _StaticCreateSelf_, we have shown how to write clean and reusable DTOs that are easy to use and maintain. These traits can be a great starting point for writing your own DTOs, allowing you to leverage the power of PHP's object-oriented features and create code that is easy to read, understand, and modify.

So why not give it a try? Start using DTOs in your next project and see how they can help you write better, more maintainable code. Your future self (and your team) will thank you for it!