Data Transfer Object V3 Modernizes DTOs With PHP 8 Features

Published on by

Data Transfer Object V3 Modernizes DTOs With PHP 8 Features image

Spatie's Data Transfer Object (DTO) package makes constructing objects from arrays a breeze, giving you confidence in the data contained therein. I've been a fan of this package since learning about the initial V1 release, and I hope you'll consider this package for passing around data in your application.

The DTO package just released V3 with all of the PHP 8 goodies we've only dreamed of up to this point. For those just starting to use or consider PHP 8 in your projects, the source code of the V3 DTO package is an excellent resource with real-world examples of helpful PHP 8 features.

I want to congratulate the principal author Brent Roose and Spatie for moving forward with this excellent package with the features in the V3 release.

Here are some of the main features taken from the readme available in V3:

  • Named arguments
  • Value Casts - convert properties typed as a DTO from array data to the DTO instance automatically
  • Custom Casts - you can build your custom caster classes
  • Strict DTOs
  • Helper functions
  • Runtime type checks are gone in favor of PHP 8's type system

If you want all the details of the above features, check out the project's readme.

While the DTO package readme delves into the more complex use-cases this package supports, here's a simple example back from V1 of what you might expect from this package for those not familiar with the DTO package:

class PostData extends DataTransferObject
{
/** @var string */
public $title;
 
/** @var string */
public $body;
 
/** @var int */
public $author_id;
}
 
$postData = new PostData([
'title' => '…',
'body' => '…',
'author_id' => '…',
]);
 
$postData->title;
$postData->body;
$postData->author_id;

As you can see, we can pass array data to the constructor, which (at the time of V1) checks types at runtime and constructs a PostData instance or fails in an exception if the data is not valid.

With the release of typed properties in PHP 7.4 and named arguments and union types in PHP 8, Spatie's V3 of the DTO package leverages many new language features. Taking the simple example above, here's what it might look like in a PHP 8 version:

use Spatie\DataTransferObject\DataTransferObject;
 
class PostData extends DataTransferObject
{
public string $title;
public string $body;
public int $author_id;
}
 
// Named arguments FTW
$post = new PostData(
title: 'Hello World',
body: 'This is a test post.',
author_id: 1
);
 
echo $post->title, "\n";
echo $post->body, "\n";
echo $post->author_id, "\n";

The above example is simple but illustrates well how this package's basics have evolved since V1, which supports PHP ^7.0. Note: given the above example, you might not even need to leverage the DTO package as PHP 8 takes care of the typing concerns and allows named arguments making a plain old PHP object (POPO) just as practical for this simple example.

If you haven't tried Spatie's DTO package, I hope even this simple example illustrates how you can know more about the data you transfer between objects. Imagine the above as an array of data:

$post = [
'title' => 'Hello World',
'body' => 'This is a test post.',
'author_id' => 1,
];
 
$someObject->doStuff($post);

Let's say that your doStuff implementation looks like the following to keep the example simple:

function doStuff(array $post)
{
$title = ucwords($post['title']);
$author = findAuthorById($post['author_id']);
 
echo $title, "\n";
echo htmlspecialchars($post['body']);
echo $author['name'], "\n";
}

As a consumer of doStuff(), you have no idea the shape of the required data without referencing the implementation of doStuff(). That means when you need to call doStuff(), you have to look at the function to know what array data to pass.

The maintainer of a naive doStuff() implementation assumes that the consumer is sending required data. Sending malformed or missing data results in undefined key errors that might not crop up until after you've shipped a feature. Or, if you're paranoid, you might need to check everything before you use it:

function doStuff(array $post)
{
if (empty($post['title'])) {
throw new \Exception('Missing title');
}
 
if (empty($post['body'])) {
throw new \Exception('Missing body');
}
 
if (empty($post['author_id'])) {
throw new \Exception('Missing author_id key');
}
 
$title = ucwords($post['title']);
$author = findAuthorById($post['author_id']);
 
echo $title, "\n";
echo htmlspecialchars($post['body']);
echo $author['name'], "\n";
}

Instead, you could guarantee the shape of data with a POPO or DTO (back in V1). It's just that in DTO V2 and V3, some things are now handled natively through PHP 8's language features instead of runtime checks:

function doStuff(PostData $post)
{
$author = findAuthorById($post->author_id);
 
echo $post->title, "\n";
echo htmlspecialchars($post->body);
echo $author->name, "\n";
}

IDEs understand PostData, making it easy to both use and construct new instances. In this naive example, we know what data to expect, and the DTO package ensures this data is structured as expected when the object gets constructed.

While structured, typed data might seem like a trivial boilerplate to the veteran Java developer, PHP developers are more prone to seeing associative array data passed back and forth in an application. PHP 8 and this DTO package go a long way in providing more assurances of the data passed around in your PHP applications, which I believe makes you more productive and your code more confident.

Learn More

You can learn more about this package, get full installation instructions, and view the source code on GitHub. Freek Van der Herten and Brent Roose also wrote details of the Data Transfer Object v3 features if you're looking for a more in-depth explanation and examples of the DTO package.

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

Curotec logo

Curotec

Hire the top Latin American Laravel talent. Flexible engagements, budget optimized, and quality engineering.

Curotec
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
Cut PHP Code Review Time & Bugs into Half with CodeRabbit logo

Cut PHP Code Review Time & Bugs into Half with CodeRabbit

CodeRabbit is an AI-powered code review tool that specializes in PHP and Laravel, running PHPStan and offering automated PR analysis, security checks, and custom review features while remaining free for open-source projects.

Cut PHP Code Review Time & Bugs into Half with CodeRabbit
Join the Mastering Laravel community logo

Join the Mastering Laravel community

Connect with experienced developers in a friendly, noise-free environment. Get insights, share ideas, and find support for your coding challenges. Join us today and elevate your Laravel skills!

Join the Mastering Laravel community
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
LaraJobs logo

LaraJobs

The official Laravel job board

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit
MongoDB logo

MongoDB

Enhance your PHP applications with the powerful integration of MongoDB and Laravel, empowering developers to build applications with ease and efficiency. Support transactional, search, analytics and mobile use cases while using the familiar Eloquent APIs. Discover how MongoDB's flexible, modern database can transform your Laravel applications.

MongoDB

The latest

View all →
Intervention Validation image

Intervention Validation

Read article
Enhancing Laravel Authorization with Backed Enums image

Enhancing Laravel Authorization with Backed Enums

Read article
Manage Global Data in Laravel with the World Package image

Manage Global Data in Laravel with the World Package

Read article
Implementing Custom String Identifiers in Laravel Models image

Implementing Custom String Identifiers in Laravel Models

Read article
Laravel 12.2 Introduces Custom Starter Kits image

Laravel 12.2 Introduces Custom Starter Kits

Read article
Fusion or the Art of Writing PHP Into a Vue SFC Components image

Fusion or the Art of Writing PHP Into a Vue SFC Components

Read article