avatarMoha Asghari

Summarize

Refactoring Challenge 1 (Enhanced Code Management in PHP)

In my previous post, We explored refactoring techniques to improve code quality and readability. I recommend you to review that post from here:

Final refactoring step led to bellow code:

class Order {

    private const DISCOUNT_RATE = 0.9;

    public function __construct(
       private readonly array $items=[]
    ) {}

    public function calculateTotal(): float
    {
        $subtotal = $this->calculateSubtotal();
        return $this->applyDiscount($subtotal);
    }

    private function calculateSubtotal(): int
    {
        $subtotal = 0;
        foreach ($this->items as $item) {
            $subtotal += $item->price;
        }
        return $subtotal;
    }

    private function applyDiscount($total): float
    {
        return $total * self::DISCOUNT_RATE;
    }
}

A valid question arises: How do we know that calculateSubtotal returns an integer? The answer lies in the implicit contract that prices are represented as either integers or floats. However, this leads to another question: If it's just a verbal contract, isn't there a way to enforce this type in our code?

The solution: elevate our code to a higher level of robustness by using a Data Transfer Object (DTO). A DTO ensures strong type control, enhancing the integrity and reliability of our data handling. Let’s delve into implementing the ItemDTO.

Implementing the ItemDTO

First, let’s define our ItemDTO class:

class ItemDTO {
    public function __construct(
        public readonly string $name,
        public readonly float $price
    ) {}
}

This DTO represents an item with a name and a price. It uses constructor property promotion and readonly properties introduced in PHP 8, ensuring immutability and simplicity.

Refactoring the Order Class

Now, let’s refactor our Order class to use ItemDTO:

class Order {

    private const DISCOUNT_RATE = 0.9;

    public function __construct(
        private array $items = []
    ) {}

    public function addItem(ItemDTO $item): void {
        $this->items[] = $item;
    }

    public function calculateTotal(): float {
        $subtotal = $this->calculateSubtotal();
        return $this->applyDiscount($subtotal);
    }

    private function calculateSubtotal(): float {
        $subtotal = 0;
        foreach ($this->items as $item) {
            $subtotal += $item->price;
        }
        return $subtotal;
    }

    private function applyDiscount(float $total): float {
        return $total * self::DISCOUNT_RATE;
    }
}

Key Changes:

  • We introduced addItem(ItemDTO $item) method to add items to the order. This ensures that only objects of type ItemDTO can be added, enhancing type safety.
  • calculateSubtotal() and other relevant methods are refactored to work with ItemDTO objects, simplifying data handling.

Benefits of Using DTOs:

  • Type Safety: Ensures that only the intended data structure is used.
  • Code Clarity: Makes the code more readable and easier to understand.
  • Encapsulation: Encourages data encapsulation and object-oriented principles.

Implementing DTOs in your projects can lead to cleaner, more maintainable code. I encourage you to experiment with DTOs in your own PHP applications to see the benefits firsthand.

PHP
Php Developers
Dto
Refactoring
Clean Code
Recommended from ReadMedium