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 typeItemDTO
can be added, enhancing type safety. calculateSubtotal()
and other relevant methods are refactored to work withItemDTO
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.