liteacz / dto
v0.0.1
2020-05-04 10:04 UTC
Requires
- php: >=7.2
Requires (Dev)
- guzzlehttp/guzzle: ^6.5
- phpstan/phpstan: ^0.12.18
- phpunit/phpunit: ^9.1
- sensiolabs/security-checker: ^6.0
- squizlabs/php_codesniffer: ^3.5
This package is auto-updated.
Last update: 2020-05-05 09:37:45 UTC
README
不需要阅读关于DTO动机的细节吗?
🚀 直接跳转到操作!
我们试图解决这个问题
<?php $user = $client->getUser(); // How do we access user's name? // Like this? echo $user['name']; // Or is it more like this? echo $user['first_name']; // I don't remember, it's been while... // Is it something like this? echo $user['full_name']; // Or was it camelCased?! echo $user['fullName'];
现在,有了数据传输库
<?php use \Litea\DataTransfer\DataObject; class User extends DataObject { /** * @var string * @dto-property first_name * So it was snake_case after all... */ public $fistName; /** * @var string * @dto-property LastName * And last name is PascalCased? What? * It's weird API we're dealing with, indeed. * Fortunately we can easily rename it for our purposes. */ public $lastName; } $response = $client->getUser(); $user = User::create($response); // There we go! // Now, we've got an auto-completion and everything. echo $user->firstName; echo $user->lastName;
📖 文档
以下您将找到此库的基本用法。更多详情请参阅此仓库的 docs 目录中的文档。
目录
关于
处理外部数据时,通常以非常通用和动态的形式出现,这使得在一段时间后返回代码时难以推理。
这可以通过所谓的数据传输对象(DTOs)来解决,它们提供具有静态属性的对象包装,这些属性可以提供对底层值的访问。
这些对象很快就会变得重复,在第二个或第三个DTO之后,您就会想使用好的旧CTRL+C、CTRL+V,这很容易出错且难以维护。
这是一个实际生活中的DTO对象示例,可以帮助您更好地控制传入的数据
<?php class InitCallResponse { public const REDIRECT_URL = 'redirectURL'; public const REQUEST_ID = 'requestID'; /** * @var string */ public $redirectUrl; /** * @var string */ public $requestId; /** * InitCallResponse constructor. * @param string $redirectUrl * @param string $requestId */ public function __construct(string $redirectUrl, string $requestId) { $this->redirectUrl = $redirectUrl; $this->requestId = $requestId; } /** * @param array $data * @return self * @throws MissingDataTransferPropertyException */ public static function create(array $data): self { $required = [ self::REDIRECT_URL, self::REQUEST_ID ]; foreach ($required as $field) { if (!array_key_exists($field, $data)) { throw new MissingDataTransferPropertyException(sprintf( 'Mandatory field %s is missing in response data', $field )); } } return new self( $data[self::REDIRECT_URL], $data[self::REQUEST_ID] ); } }
如您所见,当需要维护几十个这样的对象时,显然有一个改进的地方。这就是我们决定提取一些常见的DTO功能,并以此包的形式提供它们的原因。
安装
安装此库的最简单方法是使用 composer
composer require litea/dto
基本用法
没有DTO
<?php // Include composer's auto-loading features require_once __DIR__ . '/vendor/autoload.php'; $client = new \GuzzleHttp\Client(); $response = $client->request('GET', 'https://jsonplaceholder.typicode.com/posts/1'); $post = json_decode((string)$response->getBody(), true); // Now we access the data: $postId = $post['id']; $authorId = $post['authorId']; $title = $post['tilte']; // And the result: // Notice: Undefined index: authorId in index.php on line 18 // Notice: Undefined index: tilte in index.php on line 19 // What?! // We need to refer to the API documentation or run the code and // debug it to find out what does the response body actually look like. // // As you can see, this is very error prone. First we find out, that // the field for accessing author's id is actually named `userId`. // Then we might discover the typo we made and correct `tilte` to `title`.
现在假设您在应用程序中多次使用此服务。您需要特别注意不要在字段命名上犯错误或打字错误。您的IDE在这里无法帮助您。
有DTO
首先,我们需要一个表示数据的对象
<?php namespace MyApp\DTO; class Post extends \Litea\DataTransfer\DataObject { public string $id; public int $userId; }
然后,我们像往常一样获取数据
<?php // ... // first lines are the same // then we get the post: $postRaw = json_decode((string)$response->getBody(), true); // Now we wrap it up with the DTO magic: $post = MyApp\DTO\Post::create($postRaw); // Now we know the structure we are dealing with: $postId = $post->id; $authorId = $post->userId; // And then, they lived happily ever after... // The end
就是这样。如您所见,在 simplest 形式下,使用DTO对象只是定义一个扩展 Litea\DataTransfer\DataObject
的类,然后调用 MyObject::create
。