数据传输对象 V3 使用 PHP 8 功能现代化 DTO
发布于 作者 Paul Redmond
Spatie 的 数据传输对象 (DTO) 包让从数组构建对象变得轻而易举,让您对其中包含的数据充满信心。自从了解到最初的 V1 版本以来,我一直是这个包的粉丝,我希望您能考虑在您的应用程序中使用这个包来传递数据。
DTO 包刚刚发布了 V3,包含了我们一直梦寐以求的所有 PHP 8 功能。对于那些刚开始使用或考虑在项目中使用 PHP 8 的人来说,V3 DTO 包的源代码 是一个很好的资源,它提供了有用 PHP 8 功能的实际示例。
我要祝贺主要作者 Brent Roose 和 Spatie 推出了 V3 版本,并为这个优秀的包添加了新功能。
以下是 从自述文件 中获取的 V3 中的一些主要功能
- 命名参数
- 值转换 - 自动将类型为 DTO 的属性从数组数据转换为 DTO 实例
- 自定义转换 - 您可以构建自定义转换器类
- 严格的 DTO
- 辅助函数
- 运行时类型检查已被 PHP 8 的类型系统取代
如果您想了解上述所有功能的详细信息,请查看项目的 自述文件。
虽然 DTO 包的自述文件深入探讨了该包支持的更复杂的使用案例,但这里有一个来自 V1 的简单示例,说明您可以从该包中得到什么,对于那些不熟悉 DTO 包的人来说。
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;
如您所见,我们可以将数组数据传递给构造函数,它(在 V1 时代)会在运行时检查类型,并构建一个 PostData
实例,如果数据无效,则会引发异常。
随着 类型化属性 在 PHP 7.4 中的发布,以及 PHP 8 中的命名参数和联合类型,Spatie 的 V3 DTO 包利用了许多新的语言功能。以上面简单的例子为例,以下是它在 PHP 8 版本中的样子。
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";
上面的例子很简单,但很好地说明了自 V1 以来,该包的基础知识是如何演变的,V1 支持 PHP ^7.0
。注意:鉴于上面的例子,您甚至可能不需要使用 DTO 包,因为 PHP 8 处理了类型化问题,并允许命名参数,使普通 PHP 对象 (POPO) 对于这个简单的例子来说同样实用。
如果您还没有尝试过 Spatie 的 DTO 包,我希望即使是这个简单的例子也能说明您如何可以更多地了解在对象之间传输的数据。想象上面是一个数组数据
$post = [ 'title' => 'Hello World', 'body' => 'This is a test post.', 'author_id' => 1,]; $someObject->doStuff($post);
假设您的 doStuff
实现看起来像下面这样,为了使示例更简单
function doStuff(array $post){ $title = ucwords($post['title']); $author = findAuthorById($post['author_id']); echo $title, "\n"; echo htmlspecialchars($post['body']); echo $author['name'], "\n";}
作为 doStuff()
的使用者,您无法在不参考 doStuff()
的实现的情况下了解所需数据的形状。这意味着当您需要调用 doStuff()
时,您必须查看函数以了解要传递什么数组数据。
一个简单的 doStuff()
实现的维护者假设使用者正在发送所需数据。发送格式错误或缺少数据会导致未定义的键错误,这些错误可能在您发布功能后才会出现。或者,如果您很谨慎,您可能需要在使用数据之前检查所有数据
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";}
相反,您可以使用 POPO 或 DTO(回到 V1)来保证数据的形状。只是在 DTO V2 和 V3 中,某些事情现在通过 PHP 8 的语言功能而不是运行时检查来原生处理
function doStuff(PostData $post){ $author = findAuthorById($post->author_id); echo $post->title, "\n"; echo htmlspecialchars($post->body); echo $author->name, "\n";}
IDE 理解 PostData,这使得使用和构建新实例变得容易。在这个简单的例子中,我们知道要期待什么数据,并且 DTO 包确保当对象被构建时,该数据按预期结构化。
虽然结构化、类型化的数据对于经验丰富的 Java 开发人员来说似乎是微不足道的样板代码,但 PHP 开发人员更容易看到在应用程序中来回传递的关联数组数据。PHP 8 和这个 DTO 包在为您的 PHP 应用程序传递的数据提供更多保证方面走得很远,我相信这会让您更有效率,并且您的代码更自信。
了解更多
您可以在 GitHub 上了解更多关于这个包的信息,获取完整的安装说明,并查看 源代码。如果您想找一个更深入的解释和 DTO 包的示例,Freek Van der Herten 和 Brent Roose 还写了关于 数据传输对象 v3 功能的详细信息。