Sử dụng DTO để giữ ngữ cảnh

Kể từ khi phát hành PHP 8, việc tạo DTO hoặc Đối tượng chuyển miền trong các dự án của bạn cho nhiều mục đích chưa bao giờ đơn giản hơn thế

Mọi thứ đều có thể xảy ra trước PHP 8, từ việc thoát khỏi cấu trúc cơ bản của Mảng đến việc thêm kiểu an toàn vào mảng trước đây chỉ là một mảng cũ đơn giản;

Các tùy chọn của chúng tôi trong hệ sinh thái PHP đang mở rộng nhanh chóng khi PHP 8. 2 cách tiếp cận. Hướng dẫn về Phong cách Thiết kế Đối tượng của Matthias Noback là một cuốn sách tuyệt vời để đọc và tôi khuyên tất cả các nhà phát triển nên làm như vậy ít nhất một lần

Tuy nhiên, tôi gọi chúng là Đối tượng dữ liệu vì chúng là như vậy, không phải DTO vì tôi chỉ sử dụng chúng trong mã miền của mình. Tôi sẽ gọi chúng là Đối tượng dữ liệu trong phần còn lại của hướng dẫn này

Điều này mang lại cho tôi một cấu trúc bất biến mà tôi có thể chuyển qua ứng dụng của mình để duy trì ngữ cảnh và loại an toàn, mà tôi gọi là tình huống đôi bên cùng có lợi. Khi tạo Đối tượng Dữ liệu, tôi muốn đặt tất cả các thuộc tính ở chế độ chỉ đọc vì chúng chỉ nên được đọc chứ không được ghi — điều này làm mất đi mục đích của chúng

Để minh họa, tôi sẽ tạo Chirps bằng nguồn cảm hứng từ Laravel Bootcamp. Ngày nay, tôi sử dụng UUID hoặc ULID, tùy thuộc vào ứng dụng, khi xây dựng ứng dụng. Tiếng hót líu lo của chúng ta có hai điều nó cần quan tâm. tin nhắn của nó và người dùng đã tạo ra nó. Đối với cái này, tôi sẽ sử dụng ULID

Do đó, chúng tôi tìm cách chuyển từ logic nội tuyến trong ứng dụng của mình sang các lớp được chia sẻ để cấu trúc lại cơ sở mã Bootcamp để giúp quản lý đơn giản hơn trong thời gian dài - giao diện web, API, CLI, v.v. Hãy xem xét điều này chi tiết hơn

_10

Chúng tôi có thể cấu trúc lại điều này để quá trình tạo diễn ra ở một nơi khác và chúng tôi thực hiện xác thực trong Yêu cầu biểu mẫu

________Đầu tiên

Có thể hơi khó đọc vì chúng tôi đang xử lý mọi thứ ở đây trong một lần, vì vậy hãy chia nhỏ nó

1$chirp = $this->command->handle[
2 chirp: $request->validated[],
3];

Điều này có thể chấp nhận được và không có lý do gì để đi xa hơn nữa;

Làm thế nào để tiếng hót líu lo của chúng tôi xuất hiện?

1final class ChirpObject implements DataObjectContract
2{
3 public function __construct[
4 public readonly string $user,
5 public readonly string $message,
6 ] {}
7 
8 public function toArray[]: array
9 {
10 return [
11 'message' => $this->message,
12 'user_id' => $this->user,
13 ];
14 }
15}

Nó triển khai một giao diện có tên _17 từ một trong các gói Laravel mà tôi thường đưa vào một dự án và theo kiểu Steve điển hình, đây là lớp cuối cùng. Sau đó, tôi có một phương thức tên là _________, được thực thi bởi giao diện và đó là cách để tôi triển khai cách gửi đối tượng này tới Eloquent. Mỗi thuộc tính là công khai và có thể truy cập bên ngoài lớp, nhưng chúng cũng chỉ đọc để bối cảnh của tôi không thể thay đổi ngay khi đối tượng được tạo

Thông qua việc sử dụng một đối tượng theo ngữ cảnh và loại an toàn bổ sung được cung cấp bởi phương pháp này, tôi có thể tự tin truyền dữ liệu xung quanh ứng dụng của mình. Bộ điều khiển của chúng ta bây giờ trông như thế nào?

1public function __invoke[StoreRequest $request]: Response
2{
3 return new JsonResponse[
4 data: $this->command->handle[
5 chirp: new ChirpObject[
6 user: strval[auth[]->id[]],
7 message: strval[$request->get['message']],
8 ],
9 ],
10 status: Http::CREATED->value,
11 ];
12}

Chúng tôi có thể muốn bọc mã của mình trong một khối thử bắt để phát hiện bất kỳ sự cố tiềm ẩn nào, nhưng đó không hoàn toàn là vấn đề tôi đang cố gắng thực hiện ngay bây giờ. Tôi nghĩ rằng mã này là lý tưởng

Cho đến nay, vấn đề lớn nhất mà tôi gặp phải là việc tạo Đối tượng Dữ liệu đôi khi có thể rất tẻ nhạt, đặc biệt là khi chúng ngày càng lớn hơn. Nếu tôi đang làm việc trong một ứng dụng lớn hơn có Đối tượng dữ liệu lớn hơn, tôi sẽ thực hiện một cách tiếp cận hơi khác. Mặc dù tôi sẽ không sử dụng nó trong trường hợp này, tuy nhiên tôi sẽ chứng minh cách bạn có thể sử dụng để chỉ cho bạn cách

_15

Bằng cách xây dựng một nhà máy sản xuất đối tượng dữ liệu, chúng tôi có thể quản lý việc tạo đối tượng dữ liệu và sửa đổi các yêu cầu đến để phù hợp hơn với nhu cầu của ứng dụng của chúng tôi. Chúng ta hãy xem xét kỹ hơn những gì nhà máy sản xuất đối tượng dữ liệu sẽ đòi hỏi

_16

Mặc dù chúng chỉ là các lớp cơ bản chuyển đổi mảng yêu cầu thành một đối tượng khi tải trọng yêu cầu tăng lên, nhưng chúng hỗ trợ làm sạch mã bộ điều khiển của bạn

Bạn đã khám phá ra những cách sáng tạo để sử dụng Đối tượng Dữ liệu chưa?

DTO, hoặc Đối tượng chuyển miền, có thể được sử dụng cho rất nhiều. Kể từ khi PHP 8 được phát hành, việc tạo các lớp tuyệt vời này trong các dự án của bạn chưa bao giờ dễ dàng hơn thế

Từ việc thoát khỏi cấu trúc cơ bản của Mảng đến việc thêm kiểu an toàn vào thứ từng chỉ là một mảng cũ đơn giản. Trước PHP 8, mọi thứ đều có thể thực hiện được;

Với PHP8. 2 sắp xuất hiện, các tùy chọn của chúng tôi ngày càng mở ra nhiều hơn trong hệ sinh thái PHP. Một cuốn sách tuyệt vời để đọc là Object Design Style Guide của Matthias Noback, mà tôi khuyên tất cả các nhà phát triển nên đọc ít nhất một lần

Tuy nhiên, tôi không gọi các DTO này vì tôi không chỉ sử dụng chúng trong mã miền của mình. Thay vào đó, tôi gọi những Đối tượng Dữ liệu này, vì đó là những gì chúng là. Trong phần còn lại của hướng dẫn này, tôi sẽ gọi chúng là Đối tượng dữ liệu

Khi tạo Đối tượng dữ liệu, tôi muốn làm cho tất cả các thuộc tính ở chế độ chỉ đọc vì chúng chỉ nên được đọc chứ không phải được ghi - điều này đánh bại quan điểm của chúng. Điều này mang lại cho tôi một cấu trúc bất biến mà tôi có thể chuyển qua ứng dụng của mình để giữ an toàn cho ngữ cảnh và loại - mà tôi gọi là tình huống đôi bên cùng có lợi

Hãy xem một ví dụ. Tôi sẽ mượn ý tưởng từ Laravel Bootcamp và tạo Chirps. Chirp của chúng ta có hai thứ mà nó cần quan tâm, đó là thông điệp của nó và người dùng đã tạo ra nó. Ngày nay, khi xây dựng ứng dụng, tôi sử dụng UUID hoặc ULID, tùy thuộc vào ứng dụng. Trong phần này, tôi sẽ sử dụng ULID

Vì vậy, chúng tôi muốn cấu trúc lại cơ sở mã Bootcamp để dễ quản lý hơn về lâu dài - giao diện web, API, CLI, v.v. Vì vậy, chúng tôi tìm cách chuyển từ logic nội tuyến trong ứng dụng của mình sang các lớp dùng chung. Hãy xem nó trông như thế nào

1$validated = $request->validate[[

2 'message' => 'required|string|max:255',

3]];

4 

5$request->user[]->chirps[]->create[$validated];

6 

7return redirect[route['chirps.index']];

Chúng tôi có thể cấu trúc lại điều này để chúng tôi thực hiện xác thực của mình trong Yêu cầu biểu mẫu và chuyển quá trình tạo sang một thứ khác

1public function __invoke[StoreRequest $request]: Response

2{

3 return new JsonResponse[

4 data: $this->command->handle[

5 chirp: $request->validated[],

6 ],

7 status: Http::CREATED->value,

8 ];

9}

Ở đây chúng tôi đang quay lại và xử lý mọi thứ trong một lần - điều này có thể khiến nó hơi khó đọc, vì vậy hãy tách nó ra

1$chirp = $this->command->handle[

2 chirp: $request->validated[],

3];

Điều này là tốt, và không có lý do gì bạn phải đi xa hơn thế này. Tuy nhiên, nếu bạn muốn làm nhiều hơn và bắt đầu thêm ngữ cảnh, thì bạn có thể bắt đầu thêm các Đối tượng Dữ liệu - theo ý kiến ​​của tôi - rất tốt để sử dụng

Tiếng kêu của chúng ta nên trông như thế nào?

1final class ChirpObject implements DataObjectContract

2{

3 public function __construct[

4 public readonly string $user,

5 public readonly string $message,

6 ] {}

7 

8 public function toArray[]: array

9 {

10 return [

11 'message' => $this->message,

12 'user_id' => $this->user,

13 ];

14 }

15}

Vì vậy, theo phong cách điển hình của Steve, đây là lớp học cuối cùng. Nó triển khai một giao diện có tên là

1final class ChirpObject implements DataObjectContract
2{
3 public function __construct[
4 public readonly string $user,
5 public readonly string $message,
6 ] {}
7 
8 public function toArray[]: array
9 {
10 return [
11 'message' => $this->message,
12 'user_id' => $this->user,
13 ];
14 }
15}
0, xuất phát từ một trong các gói Laravel mà tôi thường kéo vào một dự án. Mỗi thuộc tính là công khai và có thể truy cập bên ngoài lớp, nhưng chúng cũng chỉ đọc để bối cảnh của tôi không thể thay đổi ngay khi đối tượng được tạo. Sau đó, tôi có một phương thức tên là
1final class ChirpObject implements DataObjectContract
2{
3 public function __construct[
4 public readonly string $user,
5 public readonly string $message,
6 ] {}
7 
8 public function toArray[]: array
9 {
10 return [
11 'message' => $this->message,
12 'user_id' => $this->user,
13 ];
14 }
15}
1, được thực thi bởi giao diện và đó là cách để tôi triển khai cách gửi đối tượng này tới Eloquent

Sử dụng phương pháp này cho phép tôi sử dụng một đối tượng theo ngữ cảnh và thêm loại an toàn bổ sung cho ứng dụng. Điều này có nghĩa là tôi có thể yên tâm khi chuyển dữ liệu xung quanh ứng dụng của mình. Bộ điều khiển của chúng ta bây giờ trông như thế nào?

1public function __invoke[StoreRequest $request]: Response

2{

3 return new JsonResponse[

4 data: $this->command->handle[

5 chirp: new ChirpObject[

6 user: strval[auth[]->id[]],

7 message: strval[$request->get['message']],

8 ],

9 ],

10 status: Http::CREATED->value,

11 ];

12}

Mã này, với tôi, là lý tưởng. Chúng tôi có thể muốn bọc mã của mình trong một khối thử bắt để phát hiện bất kỳ sự cố tiềm ẩn nào, nhưng đó không hoàn toàn là vấn đề mà tôi đang cố gắng giải quyết ngay bây giờ

Cho đến nay, vấn đề lớn nhất mà tôi nhận thấy là việc tạo Đối tượng Dữ liệu đôi khi hơi khó khăn, đặc biệt là khi chúng lớn hơn. Nếu tôi đang làm việc trong một ứng dụng lớn hơn, trong đó Đối tượng dữ liệu lớn hơn, tôi sẽ sử dụng một cách tiếp cận hơi khác. Trong ví dụ này, tôi sẽ không sử dụng nó. Tuy nhiên, để chỉ cho bạn cách bạn có thể sử dụng nó - tôi sẽ chỉ cho bạn cái này ngay bây giờ

________số 8

Tạo Nhà máy đối tượng dữ liệu sẽ cho phép chúng tôi kiểm soát cách tạo Đối tượng dữ liệu và cho phép chúng tôi chuyển đổi yêu cầu đến thành thứ gì đó gần hơn với cách chúng tôi muốn làm việc trong ứng dụng của mình. Hãy xem Data Object Factory trông như thế nào

1final class ChirpFactory implements ChirpFactoryContract

2{

3 public function make[array $data]: DataObjectContract

4 {

5 return new ChirpObject[

6 user: strval[data_get[$data, 'user']],

7 message: strval[data_get[$data, 'message']],

8 ];

9 }

10}

Chúng chỉ là các lớp đơn giản lấy mảng yêu cầu để biến nó thành một đối tượng, nhưng khi tải trọng yêu cầu lớn hơn, chúng sẽ giúp làm sạch mã bộ điều khiển của bạn

Bạn đã tìm thấy những cách thú vị để sử dụng Đối tượng Dữ liệu chưa? . Hãy cho chúng tôi biết suy nghĩ của bạn trên Twitter

Chủ Đề