首頁  >  文章  >  後端開發  >  探索資料傳輸物件 (DTO) 的優勢以及 PHP 只讀類別如何提升您的 Laravel 程式碼

探索資料傳輸物件 (DTO) 的優勢以及 PHP 只讀類別如何提升您的 Laravel 程式碼

PHPz
PHPz原創
2024-07-30 08:59:091159瀏覽

Explore the Advantages of Data Transfer Objects (DTOs) and How PHP  Readonly Classes Can Elevate Your Laravel Code

在現代 Web 應用程式開發中,高效、安全地管理和傳輸資料至關重要。對此流程有顯著幫助的設計模式是資料傳輸物件 (DTO)。這篇文章將深入探討使用 DTO 的優勢,特別是在 Laravel 應用程式中,並展示 PHP 8.2 只讀類別如何進一步增強其優勢。

什麼是資料傳輸物件 (DTO)?

資料傳輸對象(DTO)是一個簡單的對象,旨在在進程或系統之間傳輸資料。與典型的模型或實體不同,DTO 不受業務邏輯的影響。它們封裝數據,提供一種清晰且結構化的方式在應用程式的不同層或不同系統之間傳輸資訊。

DTO模式

DTO 模式用於在軟體應用程式內的不同子系統之間傳輸資料。使用 DTO 的主要目標是最大限度地減少方法呼叫的數量、聚合必要的資料並提供結構化方法來管理資料轉換和驗證。

使用 DTO 的好處

  • 關注點分離: DTO 將業務邏輯與資料表示隔離,從而產生更清晰、更易於維護、更易於理解的程式碼。

  • 資料驗證:DTO 允許在其他應用程式層處理資料之前對資料進行驗證,確保僅使用有效資料。

  • 一致性:透過提供一致的資料傳輸結構,DTO 簡化了來自各種來源的資料的管理和處理。

  • 安全性:DTO 可以透過控制哪些資料可存取和可修改來保護您的應用程式免受未經授權的資料操縱。

  • 測試:由於 DTO 是沒有嵌入業務邏輯的簡單對象,因此它們更容易模擬和測試。

  • 轉換:DTO 有助於將資料轉換為不同應用層所需的格式。

  • 不變性: DTO 通常會促進不變性,這意味著一旦創建,它們的狀態就無法更改。此功能帶來了幾個優點:

    • 可預測性: 不可變物件是可預測的且更容易推理,因為它們的狀態在創建後保持不變。
    • 線程安全:不變性本質上支援線程安全,簡化並發處理。
    • 偵錯:使用不可變物件進行偵錯更容易,因為它們的狀態保證在整個生命週期中保持不變。

PHP 8.2 和唯讀類

在 PHP 8.2 中,唯讀類別的引入增強了 DTO 的使用。只讀類別無需將屬性明確定義為唯讀,從而簡化了 DTO 實作。以下是 PHP 8.2 的唯讀類別如何改善 DTO:

  • 簡化程式碼:只讀類別自動使屬性不可變,減少樣板程式碼並提高清晰度。
  • 增強的安全性:確保屬性一旦設定就無法修改,只讀類別增強了資料完整性和安全性。
  • 提高可維護性:使用唯讀類別可以產生更乾淨、更易於維護的程式碼,因為資料的不變性是由語言本身強制執行的。

範例:在物業管理系統中使用 DTO

讓我們考慮一個屬性管理系統,其中屬性可以來自各種來源,例如 API 和 CSV 導入。我們可以使用 DTO 建立屬性模型、訂閱、資產等,確保資料在整個應用程式中保持一致並經過驗證。

定義 PropertyDTO

首先,我們定義一個PropertyDTO類別:

app/DTO/PropertyDTO.php

namespace App\DTO;

/**
 * Class PropertyDTO
 *
 * Represents a Data Transfer Object for property data.
 */
readonly class PropertyDTO extends AbstractDTO
{
    /**
     * The name of the property.
     *
     * @var string
     */
    public string $name;

    /**
     * The address of the property.
     *
     * @var string
     */
    public string $address;

    /**
     * The price of the property.
     *
     * @var float
     */
    public float $price;

    /**
     * The subscription status of the property, if applicable.
     *
     * @var string|null
     */
    public ?string $subscription;

    /**
     * The list of assets associated with the property.
     *
     * @var array|null
     */
    public ?array $assets;

    /**
     * Set the properties from a model instance.
     *
     * @param $model The model instance.
     * @return $this
     */
    public function setFromModel($model): self
    {
        $this->name = $model->name;
        $this->address = $model->address;
        $this->price = $model->price;
        $this->subscription = $model->subscription;
        $this->assets = $model->assets;

        return $this;
    }

    /**
     * Set the properties from API data.
     *
     * @param array $data The API data.
     * @return $this
     */
    public function setFromAPI(array $data): self
    {
        $this->name = $data['property_name'];
        $this->address = $data['property_address'];
        $this->price = $data['property_price'];
        $this->subscription = $data['subscription'] ?? null;
        $this->assets = $data['assets'] ?? null;

        return $this;
    }

    /**
     * Set the properties from CSV data.
     *
     * @param array $data The CSV data.
     * @return $this
     */
    public function setFromCSV(array $data): self
    {
        $this->name = $data[0];
        $this->address = $data[1];
        $this->price = (float) $data[2];
        $this->subscription = $data[3] ?? null;
        $this->assets = explode(',', $data[4] ?? '');

        return $this;
    }
}
使用 PropertyDTO

以下是如何使用 PropertyDTO 處理來自不同來源的屬性:

// From a Model
$model = Property::find(1);
$propertyDTO = (new PropertyDTO([]))->setFromModel($model);

// From an API
$apiData = [
    'property_name' => 'Beautiful House',
    'property_address' => '1234 Elm Street',
    'property_price' => 450000,
    'subscription' => 'Premium',
    'assets' => ['pool', 'garden']
];
$propertyDTO = (new PropertyDTO([]))->setFromAPI($apiData);

// From a CSV
$csvData = ['Beautiful House', '1234 Elm Street', 450000, 'Premium', 'pool,garden'];
$propertyDTO = (new PropertyDTO([]))->setFromCSV($csvData);

// Convert to Array
$arrayData = $propertyDTO->toArray();

// Convert to JSON
$jsonData = $propertyDTO->toJson();

概括

資料傳輸物件 (DTO) 透過確保資料一致性、驗證和關注點分離,在 Laravel 應用程式中提供了眾多優勢。透過實施 DTO,您可以使應用程式更易於維護、更安全且更易於測試。在物業管理系統中,DTO 有助於高效處理來自各種來源(例如 API 和 CSV 導入)的數據,確保您的業務邏輯保持乾淨並專注於處理經過驗證的數據。

Moreover, embracing immutability within DTOs enhances predictability, thread-safety, and simplifies debugging.

Extending DTOs with Abstract Classes for Consistency

To streamline the creation of DTOs and promote code reuse, we can use an abstract class or base class. This approach allows us to define common methods and properties in the abstract class and extend it for specific data sources.

Defining the AbstractDTO

app/DTO/AbstractDTO.php

namespace App\DTO;

/**
 * AbstractDTO
 *
 * An abstract base class for Data Transfer Objects (DTOs).
 * Provides common methods and properties for DTO implementations.
 */
abstract class AbstractDTO
{
    /**
     * AbstractDTO constructor.
     *
     * Initialises the DTO with data from an associative array.
     *
     * @param array $data The data array to initialize the DTO.
     */
    public function __construct(array $data)
    {
        $this->setFromArray($data);
    }

    /**
     * Set the properties of the DTO from a model instance.
     *
     * @param $model The model instance from which to populate the DTO.
     * @return $this
     */
    abstract public function setFromModel($model): self;

    /**
     * Set the properties of the DTO from API data.
     *
     * @param array $data The data array from the API.
     * @return $this
     */
    abstract public function setFromAPI(array $data): self;

    /**
     * Set the properties of the DTO from CSV data.
     *
     * @param array $data The data array from the CSV.
     * @return $this
     */
    abstract public function setFromCSV(array $data): self;

    /**
     * Convert the DTO to an associative array.
     *
     * @return array The DTO data as an associative array.
     */
    public function toArray(): array
    {
        $properties = get_object_vars($this);
        return array_filter($properties, function ($property) {
            return $property !== null;
        });
    }

    /**
     * Convert the DTO to a JSON string.
     *
     * @return string The DTO data as a JSON string.
     */
    public function toJson(): string
    {
        return json_encode($this->toArray());
    }

    /**
     * Set the properties of the DTO from an associative array.
     *
     * @param array $data The data array to populate the DTO.
     */
    protected function setFromArray(array $data): void
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }
}

Final Thoughts

Using an abstract or base class for DTOs not only ensures consistency across different DTO implementations but also promotes code reuse and maintainability. By defining common methods and properties in an abstract class, you can create a structured and efficient way to manage data transfer within your application. This approach aligns well with the principles of clean code and helps in building scalable and robust applications.

Here’s a revised phrase that includes a call to action:

"By leveraging DTOs and abstract classes together, you can refine your Laravel application's design, improving how data is managed and ensuring a more organised and efficient data flow. If you want to further encapsulate and enhance your DTOs with traits and interfaces, explore our guide on Enhancing Object-Oriented Design with Traits, Interfaces, and Abstract Classes."

以上是探索資料傳輸物件 (DTO) 的優勢以及 PHP 只讀類別如何提升您的 Laravel 程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn